【问题标题】:Changes not being observed in a MutableLiveData List在 MutableLiveData 列表中未观察到更改
【发布时间】:2020-06-08 06:55:31
【问题描述】:

我的存储库中有一个 MutableLiveData 列表,如下所示:

class AnswerRepository {
    private var _answerList = mutableListOf<Answer>()
    var answerList = MutableLiveData<MutableList<Answer>>()

    fun addAnswerInList(answer: Answer) {
        _answerList.add(answer)
        answerList.value = _answerList
        Log.e("AnswerRepository", "Answer List size : ${answerList.value?.size}")
        Log.e("AnswerRepository", "_Answer List Size : ${_answerList.size}")
    }

    fun returnAnswerList(): MutableLiveData<MutableList<Answer>> {
        return answerList
    }
}

在服务中的'answerList'(MutableLiveData 列表)中添加了一个项目,如下所示:

class FloatingWidgetService : Service(), View.OnClickListener{
    private val answerRepository = AnswerRepository()

    @SuppressLint("InflateParams")
    override fun onCreate() {
        super.onCreate()

        //Getting the widget layout from xml using layout inflater
        mFloatingView = LayoutInflater.from(this).inflate(R.layout.floating_widget, null)


        initialiseViews()

        setListeners()
}

         @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onClick(p0: View?) {

        when (p0?.id) {
            R.id.next -> {
                addItemInList()
            }
        }

    private fun addItemInList(){
           val answer = Answer(questionNumber, selectedOption, questionStatus)
                    answerRepository.addAnswerInList(answer)
}

然后使用存储库和片段之间的视图模型在片段中观察到这个 MutableLiveData 列表 (answersList),如下所示:

视图模型:

class SendAnswerToCloudViewModel : ViewModel() {

    private val answerRepository = AnswerRepository()

    val answerList  = answerRepository.returnAnswerList()
}

片段:

类 SendAnswerToCloud : Fragment() {

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val binding: FragmentSendDataToCloudBinding = DataBindingUtil.inflate(
        inflater,
        R.layout.fragment_send_data_to_cloud,
        container,
        false
    )

    binding.lifecycleOwner = this

    viewModel.answerList.observe(viewLifecycleOwner, Observer {
        Log.e("SendAnswerToCloud", "isChangeTrigerred")
        val answer = viewModel.answerList.value?.last()
        Log.e(
            "SendAnswerToCloud",
            "QuestionNumber : ${answer?.questionNumber}, SelectedOption : ${answer?.selectedOption}, QuestionStatus : ${answer?.questionStatus}"
        )
    })


    return binding.root
}

}

当在服务中调用addAnswerInList 时,列表在存储库中成功更新。然而,片段中什么也没有发生(因为日志没有出现在 logcat 中)。

那么,我做错了什么?任何形式的帮助将不胜感激。提前致谢!!

【问题讨论】:

  • 这个val answer = viewModel.answerList.value?.last() 可能是it.last(),因为列表正在传递给观察者对象。
  • “在下面给出的服务中的 'answerList'(MutableLiveData 列表)中添加了一个项目”您在说什么服务?也许问题是您创建了一个 AnswerRepository 的新实例,它创建了另一个 MutableLiveData 并在那里发布更新。如果您可以在fun addItemInList 的位置发布更多代码。
  • 感谢@JeneaVranceanu 的评论。我更新了问题。

标签: android android-studio android-fragments kotlin


【解决方案1】:

您的实现中的问题是您实例化了两个AnswerRepository 对象而不是一个。因此,你会得到两个 var answerList = MutableLiveData&lt;MutableList&lt;Answer&gt;&gt;() 而不是一个。当您的SendAnswerToCloud 云监听第一个answerList 的更改时,您的服务编辑另一个answerList。这就是您看不到任何变化的原因。

确保只创建一个AnswerRepository 对象。

在编程中,人们使用dependency injection 并可选择与singleton pattern 结合使用。有时你可以只使用单例模式,但这是一个不太灵活的解决方案,也不太容易测试。

详细回复

所以问题出现是因为您在FloatingWidgetService 类中有第一个对象实例化:

class FloatingWidgetService : Service(), View.OnClickListener{
    private val answerRepository = AnswerRepository() 
    ...

以及SendAnswerToCloudViewModel 类中的第二个实例化:

class SendAnswerToCloudViewModel : ViewModel() {
    private val answerRepository = AnswerRepository()
    ...
}

这样您就可以创建两个完全独立的对象。它们中的每一个在内存中占用不同的地址,而你在AnswerRepository中创建的所有对象在这两个实例之间也是不同的。

想象一下像这样一个接一个地放置这些声明:

class SendAnswerToCloudViewModel : ViewModel() {
    private val answerRepository = AnswerRepository()
    private val answerRepository_second = AnswerRepository() 
    ...
}

如果您稍后通过equals 方法或== 运算符比较它们,您将得到结果false,因为它们是两个不同的对象。因此,如果您将新值设置为answerRepository 中的answerList,则存储在answerRepository_second 中的answerList 的订阅者将不会收到任何更新

解决方案

添加伴随对象并将主构造函数设为私有。

class AnswerRepository private constructor() {
    companion object {
        private var INSTANCE: AnswerRepository? = null

        fun getInstance(): AnswerRepository {
            if (INSTANCE == null) {
                INSTANCE = AnswerRepository()
            }
            return INSTANCE!!
        }
    }

    private var _answerList = mutableListOf<Answer>()
    var answerList = MutableLiveData<MutableList<Answer>>()

    fun addAnswerInList(answer: Answer) {
        _answerList.add(answer)
        answerList.value = _answerList
        Log.e("AnswerRepository", "Answer List size : ${answerList.value?.size}")
        Log.e("AnswerRepository", "_Answer List Size : ${_answerList.size}")
    }

    fun returnAnswerList(): MutableLiveData<MutableList<Answer>> {
        return answerList
    }
}

现在不再使用构造函数调用来编写声明:

    private val answerRepository = AnswerRepository()

你会调用getInstance()方法得到AnswerRepository

    private val answerRepository = AnswerRepository.getInstance()

这种模式称为单例。当您确保您的程序只有一个特定类的实例时。

强烈建议您完成 Essentials 和 Kotlin 映射here

【讨论】:

  • 谢谢@JeneaVranceanu!实际上我是 android 新手,我不明白我在哪里实例化两个 AnswerRepository 对象。如果您能指出我在哪里创建这两个实例(以及我应该省略哪一个),那将非常非常有帮助。再次感谢 。 ?
  • @IqbalSingh,我已经更新了答案。请确保您熟悉编程中最重要的内容。我在 Jet Brains Academy 中亲自完成了 Kotlin 地图和部分 Essentials 地图:hyperskill.org/knowledge-map/357?v=table 该资源对任何开始编程和学习 Kotlin 的人都非常有帮助。不过,他们需要在 2021 年 1 月 1 日之后付款。现在它是免费的,所以不要错过。
  • 嗨@JeneaVranceanu,非常感谢你的爱! ? 我真的很感谢你的时间和努力。你提供资源真是太棒了。这真的很有帮助。再次感谢,并希望你有一个美好的一天。 ??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多