使用 Kotlin 从 Android 上 ViewModel 中的 LiveData 更新 ListView 中的元素

Posted

技术标签:

【中文标题】使用 Kotlin 从 Android 上 ViewModel 中的 LiveData 更新 ListView 中的元素【英文标题】:Update element in ListView from LiveData in ViewModel on Android using Kotlin 【发布时间】:2021-01-18 12:30:54 【问题描述】:

我正在制作一个由单个活动组成的应用程序。

用户可以通过单击一个按钮来创建一个预定义大小的数组。通过另一个按钮,我希望使用各种算法对数组进行排序。

算法及其执行时间显示在ListView 中。请参阅下面的屏幕截图作为示例:

我的listViewMainActivity 中是这样创建的:

listView.adapter = MyCustomAdapter(this)

以下是适配器代码:

class MyCustomAdapter(context: Context): BaseAdapter() 

    private val mContext: Context = context

    val names = MainActivityViewModel().allAlgorithms

    override fun getCount(): Int 
        return names.size
    

    override fun getItem(p0: Int): Any 
        return names[p0]
    

    override fun getItemId(p0: Int): Long 
        return p0.toLong()
    

    override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View 

        val layoutInflater = LayoutInflater.from(mContext)
        val row = layoutInflater.inflate(R.layout.row_algorithm, p2, false)

        val nameTextView = row.findViewById<TextView>(R.id.algoName)
        nameTextView.text = names[p0].name

        val timer = row.findViewById<TextView>(R.id.timer)
        timer.text = names[p0].time

        return row
    

来自我的ViewModelallAlgorithmsMutableList&lt;Algorithm&gt;

算法类:

class Algorithm(var name: String, var time: String = "0.00 sec")

目前,此MutableList&lt;Algorithm&gt; 使用listOf(various algo names) 进行初始化。这意味着时间保持为默认值。

现在当用户点击开始基准测试按钮时,这个函数在我的ViewModel中被调用:

private var _executionTime = MutableLiveData<Long>(timer)
val executionTime: LiveData<Long>
    get() = _executionTime

private var _index = MutableLiveData(0)
val index: LiveData<Int>
    get() = _index

fun startBench() 
    for ((i,v) in names.withIndex()) 
        _executionTime.value = measureTimeMillis 
            arr.sort() // is the arr generated by clicking the button
        
        _index.value = i
    

稍后我将为每种算法创建不同的函数,但现在我希望将我的ListView 更新为我的executionTime.value() 以获得正确的算法。

我试图在我的适配器中放置一个观察者,但我无法获得ViewModelProvider,因为我没有找到访问 LifeCycleOwner 的方法。

我也尝试过更新我的allAlgorithm 列表,但它当然不会更新 UI。

我的问题:

如何使用 LiveData 更新我的 ListView? 有没有更好的方法来实现我想要实现的目标?

【问题讨论】:

【参考方案1】:

我以前也遇到过类似的情况。我想虽然适配器生命周期与活动生命周期紧密相关,所以我可以将 LifecycleOwner 传递给适配器并且它工作得很好

我什至在我的列表中插入了 500 多个 Item 来测试性能,每个列表项都持有一个 LiveData 观察者,我没有发现任何问题。

也许这不是最好的解决方案,但至少你可以试一试

【讨论】:

感谢您的回答。你能解释一下你是如何通过 lifeCycleOwner 的吗?另外,您是否在任何地方使用过 notifyDataSetChanged ?【参考方案2】:

我犯了一个非常明显的错误,导致我的 notifyDataSetChanged() 不起作用:

MyCustomAdapter 中,我没有传递MainActivityViewModel 的原始版本,而是在每个不智能的调用中实例化新的viewModel

简单的解决方法是将我的 MainActivityViewModel 实例传递给适配器,如下所示:

    val adapter = MyCustomAdapter(this, viewModel)
    listView.adapter = adapter

并相应地修改适配器:

class MyCustomAdapter(context: Context, vm: MainActivityViewModel): BaseAdapter()

并考虑了更改。

【讨论】:

以上是关于使用 Kotlin 从 Android 上 ViewModel 中的 LiveData 更新 ListView 中的元素的主要内容,如果未能解决你的问题,请参考以下文章

从Kotlin的类开始说起

无法使用 Kotlin Retrofit 将数据从 Android 插入到 Mysql [重复]

Kotlin会在Android领域取代Java吗?

Kotlin史上超强二合一,Kotlin从入门到精通+高级Kotlin强化实战(附Demo)

如何在 Android Studio 中使用 Kotlin 从 Firestore 数据库中获取下一条和上一条数据?

将 Android API 从 27 降级到 21 (KOTLIN) 后出错