【问题标题】:Android Jetpack: Observing ArrayList not workingAndroid Jetpack:观察 ArrayList 不起作用
【发布时间】:2018-06-09 00:31:12
【问题描述】:

我想设置一个基本的ViewModel 并存储一个ArrayList,可以更新并因此观察,将其存储为LiveData

问题是 ViewModel 附加的 Fragment 在调用 .observe 时似乎无法检测到我的 ArrayList 中的更改。虽然当我调试应用程序时,我可以看到名为 s2 的 ArrayList 确实已更新。

这是我的 ViewModel:

class MainViewModel : ViewModel() {
    private val _s1 = MutableLiveData<String>()
    private val _s2 = MutableLiveData<ArrayList<String>>()
    val s1: LiveData<String>
        get() = _s1
    val s2: LiveData<ArrayList<String>>
        get() = _s2

    init {
        _s1.value = "HELLO WORLD"
        _s2.value = arrayListOf("")
    }

    fun populateList() {
        _s2.value?.clear()
        for (i in 10 downTo 1) {
            _s2.value?.add("$i bottles")
        }
    }
}

以及附加的片段:

class MainFragment : Fragment() {

    companion object {
        fun newInstance() = MainFragment()
    }

    private lateinit var viewModel: MainViewModel

    private var message2TV: TextView? = null

    // ...

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)

        message2TV = view?.findViewById(R.id.message_2)

        viewModel.s1.observe(this, Observer {
            view?.findViewById<TextView>(R.id.message)?.text = it
        })

        viewModel.s2.observe(this, Observer {
            if (it != null && it.isNotEmpty()) {
                message2TV?.text = ""
                it.forEach { item -> message2TV?.append("\n$item") }
            }
        })

        message2TV?.setOnClickListener {
            viewModel.populateList()
        }
    }
}

当我调试时,我还发现 viewModel.s2.observe() 在单击 View 后没有再次调用(并且 ArrayList 更新)。只有更改屏幕方向才能让它显示列表。

请问,我错过了什么?

【问题讨论】:

    标签: android arraylist kotlin android-jetpack android-livedata


    【解决方案1】:

    LiveData 在您调用 setValuepostValue 时触发更新,并为其提供对新值的引用。它无法检测到它当前持有的对象是否在内部发生了变化,例如这个可变列表正在被修改的例子。

    现在,您的代码中没有 setValue 调用:

    _s2.value?.clear() // _s2.getValue()?.clear()
    for (i in 10 downTo 1) {
        _s2.value?.add("$i bottles") // _s2.getValue()?.add(...)
    }
    

    如果你想让它调用观察者,你可以这样做:

    class MainViewModel : ViewModel() {
        private val _s2 = MutableLiveData<List<String>>()
        val s2: LiveData<List<String>>
            get() = _s2
    
        init {
            _s2.value = listOf("")
        }
    
        fun populateList() {
            _s2.value = listOf() // this is a setValue call
            for (i in 10 downTo 1) {
                // _s2.setValue(_s2.getValue?.plus("$i bottles")
                _s2.value = _s2.value?.plus("$i bottles")
            }
        }
    }
    

    如果需要,您也可以继续使用 ArrayList,对其进行修改,然后使用相同的值再次调用 setValue,但正如您已经看到的那样,这更容易出错:

    _s2.value?.add("$i bottles")
    _s2.value = _s2.value // _s2.setValue(_s2.getValue)))
    

    【讨论】:

    • 非常感谢!我现在看到我需要setValuepostValue 才能调用观察者。为我工作:)
    • 但这不适用于 Recyclerview,因为每次更新都会创建新的参考。 NotifyDataSetChanged 不会触发,因为最后一个实例被替换为新的 Arraylist 实例。
    猜你喜欢
    • 1970-01-01
    • 2021-01-26
    • 2021-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    相关资源
    最近更新 更多