【问题标题】:Retrieve param to initiate Android vielmodel (init vs constructor)检索参数以启动 Android vielmodel(初始化与构造函数)
【发布时间】:2020-09-13 05:02:20
【问题描述】:

我正在尝试实例化我的 ViewModel,以便根据给定的参数显示不同的列表。但是,我对 init 和构造函数调用有点困惑。

以下版本给我一个MainViewModel> has no zero argument constructor 错误。

版本 1

class MainViewModel(private val param: String) : ViewModel() {

private var list: ArrayList<ModelDialogOption>? = null

val userMutableLiveData: MutableLiveData<ArrayList<ModelDialogOption>?> = MutableLiveData()

init {
    populateList()
    userMutableLiveData.value = list!!
}

private fun populateList() {

    list = ArrayList()

    when (param) {

        "Choose your age range" -> {

            list!!.add(ModelDialogOption("Prefer not to say", false))
            list!!.add(ModelDialogOption("16-39", false))
            list!!.add(ModelDialogOption("40-59", true))
            list!!.add(ModelDialogOption("60+", false))

        }

    }

}

}

第 2 版

而这给了我一个空列表没有找到参数,因为构造函数仅在初始化发生后才被调用:

class MainViewModel() : ViewModel() {

var param: String? = null
private var list: ArrayList<ModelDialogOption>? = null

val userMutableLiveData: MutableLiveData<ArrayList<ModelDialogOption>?> = MutableLiveData()

init {
    populateList()
    userMutableLiveData.value = list!!
}

constructor(param: String) : this() {
    this.param = param
    populateList()
    userMutableLiveData.value = list!!
}

private fun populateList() {

    list = ArrayList()

    when (param) {

        "Choose your age range" -> {

            list!!.add(ModelDialogOption("Prefer not to say", false))
            list!!.add(ModelDialogOption("16-39", false))
            list!!.add(ModelDialogOption("40-59", true))
            list!!.add(ModelDialogOption("60+", false))

        }

    }

}

}

这里还有一个空列表:

第 3 版

class MainViewModel() : ViewModel() {

var param: String? = null
private var list: ArrayList<ModelDialogOption>? = null

val userMutableLiveData: MutableLiveData<ArrayList<ModelDialogOption>?> = MutableLiveData()

constructor(param: String) : this() {
    this.param = param
    populateList()
    userMutableLiveData.value = list!!
}

private fun populateList() {

    list = ArrayList()

    when (param) {

        "Choose your age range" -> {

            list!!.add(ModelDialogOption("Prefer not to say", false))
            list!!.add(ModelDialogOption("16-39", false))
            list!!.add(ModelDialogOption("40-59", true))
            list!!.add(ModelDialogOption("60+", false))

        }

    }

}

}

第 4 版

这给了我列表填充,但肯定没有参数,因为没有传递任何参数,只是将它用作我的起点:

class MainViewModel : ViewModel() {

private var list: ArrayList<ModelDialogOption>? = null

val userMutableLiveData: MutableLiveData<ArrayList<ModelDialogOption>?> = MutableLiveData()

init {
    populateList()
    userMutableLiveData.value = list!!
}

private fun populateList() {

    list = ArrayList()
            list!!.add(ModelDialogOption("Prefer not to say", false))
            list!!.add(ModelDialogOption("16-39", false))
            list!!.add(ModelDialogOption("40-59", true))
            list!!.add(ModelDialogOption("60+", false))

}

}

这是我的 ViewModelFactory:

public class MyViewModelFactory implements ViewModelProvider.Factory {
    private String param;


    public MyViewModelFactory(String param) {
        this.param = param;
    }


    @NotNull
    @Override
    public <T extends ViewModel> T create(@NotNull Class<T> modelClass) {
        return (T) new MainViewModel(param);
    }
}

以这种方式启动:

private val viewModel: MainViewModel by activityViewModels {
    MyViewModelFactoryForHashMap(
        arguments?.getString("headerText")
    )
}

非常感谢。

【问题讨论】:

  • 您的版本 1 应该可以正常工作。你能包括完整的堆栈跟踪吗?
  • 您好,开头是这样的:java.lang.RuntimeException: Cannot create an instance of class com.example.covidtracker.view_models.MainViewModel
  • 连接到我的片段上的这个位 model.userMutableLiveData.observe(viewLifecycleOwner, Observer&lt;Any?&gt; { list -&gt; if (list != null) (list as Iterable&lt;*&gt;).map { if ((it as ModelDialogOption).selected == true) { etYourAge.text = it.title } } })

标签: android kotlin constructor viewmodel android-viewmodel


【解决方案1】:

既然我回答了你的last question,我对你的代码流程了解一点

您应该更新它而不是在 ViewModel 中传递参数,因为您正在与两个片段共享和收听

class CovidCheckInFragment : Fragment(R.layout.fragment_covid_check_in) {

var navController: NavController? = null
private val model: MainViewModel by  activityViewModels()
private lateinit var tartTextView:TextView


@RequiresApi(Build.VERSION_CODES.M)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    tvHeader.text = "COVID Check-in"

    navController = Navigation.findNavController(view)


    // Listeners
    etYourAge.setOnClickListener(onClick)
    etYourCounty.setOnClickListener(onClick)
    etYourLocality.setOnClickListener(onClick)

    rbFemale.setOnClickListener(onClickRb)
    rbMale.setOnClickListener(onClickRb)
    rbPreferNotToSay.setOnClickListener(onClickRb)
    
    model.userMutableLiveData.observe(viewLifecycleOwner, Observer {
        it?.let {
            it.filter {
                it.selected == true
            }.map {
                tartTextView.text = it.title
            }
        }
    })

}


private val onClick = View.OnClickListener {

    val destination: Int = R.id.action_covidCheckInFragment_to_my_dialog_fragment

    val message: String? = when (it.id) {
        R.id.etYourAge -> {
            tartTextView = etYourAge
            model.updateList("Choose your age range")
            "Choose your age range"
        }
        R.id.etYourCounty -> {
            tartTextView = etYourCounty
            model.updateList("Choose your county")
            "Choose your county"
        }
        R.id.etYourLocality -> {
            tartTextView = etYourLocality
            model.updateList("Choose your locality")
            "Choose your locality"
        }
        else -> {
            ""
        }
    }


    val bundle = bundleOf("headerText" to message)
    navController = Navigation.findNavController(it)

    navController!!.navigate(
        destination,
        bundle
    )

}


@RequiresApi(Build.VERSION_CODES.M)
private val onClickRb = View.OnClickListener {


    val list = listOf<Button>(rbFemale, rbMale, rbPreferNotToSay)

    for (i in list) {
        i.setTextColor(resources.getColor(R.color.text))
        i.background.setTint(ContextCompat.getColor(activity as MainActivity, R.color.greyEee))
    }

    if ((it as AppCompatRadioButton).isChecked) {

        it.setTextColor(resources.getColor(R.color.white))
        it.background.setTint(ContextCompat.getColor(activity as MainActivity, R.color.shadow))

    }
}

}

这是你的 MainViewModel

class MainViewModel : ViewModel() {

private var list  = ArrayList<ModelDialogOption>()

val userMutableLiveData: MutableLiveData<ArrayList<ModelDialogOption>> = MutableLiveData()

fun updateItem(position: Int) {
    val itemToUpdate = list[position]
    itemToUpdate.selected = !itemToUpdate.selected!!
    list[position] = itemToUpdate
}

fun flushItems() {
    userMutableLiveData.value = list
}

fun updateList(param: String) {
    list = ArrayList()
    when (param) {

        "Choose your age range" -> {

            list.add(ModelDialogOption("Prefer not to say", false))
            list.add(ModelDialogOption("16-39", false))
            list.add(ModelDialogOption("40-59", false))
            list.add(ModelDialogOption("60+", false))

        }

        "Choose your county" -> {

            list.add(ModelDialogOption("Prefer not to say", false))
            list.add(ModelDialogOption("County1", false))
            list.add(ModelDialogOption("County2", false))
            list.add(ModelDialogOption("County3", false))

        }
        "Choose your locality" -> {
            list.add(ModelDialogOption("Prefer not to say", false))
            list.add(ModelDialogOption("Locality1", false))
            list.add(ModelDialogOption("Locality2", false))
            list.add(ModelDialogOption("Locality3", false))
        }
    }
    flushItems()
}

}

【讨论】:

  • 嘿! :) 你真的很棒,非常感谢。帮了我两次。是的,这行得通。也许由于片段之间的共享,我尝试的方法不起作用?不确定,将尝试更深入地研究视图模型概念,看看是否可以更清楚地理解它,但现在很高兴。祝您愉快。 :)
  • 我刚刚更新了 MainViewModel,因为我们不需要在 init 中填充列表{}
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-19
  • 1970-01-01
  • 2021-11-27
  • 1970-01-01
  • 2018-08-02
  • 2012-04-11
  • 1970-01-01
相关资源
最近更新 更多