android - 为什么 ViewModel 和 Fragment 中的相同变量不同?

标签 android kotlin mvvm android-room kotlin-coroutines

我正在尝试按此顺序完成这些步骤。

  • 用数据填充我的 Room 数据库。
  • 使用当前数据库内容更新列表变量(在 ViewModel 中)。
  • 从我的 Fragment 访问列表变量(在 ViewModel 中)。

  • 执行后,我按此顺序获得 Toasts
  • 0 in MythFragment
  • 5 in MythViewModel

  • 我期望的是相同数量的元素。是否因为协程而有所不同?我必须使用 LiveData 吗?
    神话 fragment .kt
    class MythFragment : Fragment() {
    
        private lateinit var viewModel: MythViewModel
    
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_myth, container, false)
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            viewModel = ViewModelProviders.of(this).get(MythViewModel::class.java)
            viewModel.populateMyths()
            viewModel.fetchFromDatabase()
    
            Toast.makeText(activity, "${viewModel.myths.size} in MythFragment", Toast.LENGTH_SHORT)
                .show()
        }
    }
    
    MythViewModel.kt
    class MythViewModel(application: Application) : BaseViewModel(application) {
    
        var myths = listOf<Myth>()
    
        fun populateMyths() {
            launch {
                val dao = MythDatabase(getApplication()).mythDao()
    
                if (dao.getRowCount() > 0)
                    return@launch
    
                val mythList = listOf<Myth>(
                    Myth("This is the myth 1", "This is the evaluation of the myth 1"),
                    Myth("This is the myth 2", "This is the evaluation of the myth 2"),
                    Myth("This is the myth 3", "This is the evaluation of the myth 3"),
                    Myth("This is the myth 4", "This is the evaluation of the myth 4"),
                    Myth("This is the myth 5", "This is the evaluation of the myth 5")
                )
    
                dao.insertAll(
                    *mythList.toTypedArray()
                )
            }
        }
    
        fun fetchFromDatabase() {
            launch {
                myths = MythDatabase(getApplication()).mythDao().getAllMyths()
                Toast.makeText(getApplication(), "${myths.size} in MythViewModel", Toast.LENGTH_SHORT)
                    .show()
            }
        }
    }
    
    BaseViewModel.kt
    abstract class BaseViewModel(application: Application) : AndroidViewModel(application),
        CoroutineScope {
    
        private val job = Job()
    
        override val coroutineContext: CoroutineContext
            get() = job + Dispatchers.Main
    
        override fun onCleared() {
            super.onCleared()
            job.cancel()
        }
    }
    

    最佳答案

    What I expected was the same number of elements. Does it differ because of Coroutines? Do I have to use LiveData?


    是的,每次使用 launch你在另一个线程上运行一些代码。这就是为什么您的 Fragment 中仍然有 0 个元素的原因。 .最好使用LiveData ,以便您在数据更改时收到通知。
    在您的 ViewModel你可以这样做:
    private val _myths = MutableLiveData<Myth>() // keep the mutable one private
    val myths: LiveData<Myth> = _myths // expose an immutable one
    
    fun fetchFromDatabase() {
        launch {
            _myths.postValue(MythDatabase(getApplication()).mythDao().getAllMyths()) 
            Toast.makeText(getApplication(), "${myths.size} in MythViewModel", Toast.LENGTH_SHORT).show()
        }
    }
    
    在您的 Fragment 中,您观察到神话的变化:
    ...
    viewModel.populateMyths()
    viewModel.fetchFromDatabase()
    viewModel.myths.observe(viewLifecycleOwner, Observer { myths ->
        Toast.makeText(activity, "${myths.size} in MythFragment", Toast.LENGTH_SHORT).show()
    })
    
    您可以使用 livedata 使上面的代码更简洁。 builder(需要 androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0 或向上依赖):
    val myths = livedata {
        emit(MythDatabase(getApplication()).mythDao().getAllMyths())
    }
    
    那就不用打fetchFromDatabase()了也不再。

    关于android - 为什么 ViewModel 和 Fragment 中的相同变量不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62809136/

    相关文章:

    kotlin - Okio native /多平台默认路径

    android - 从安卓内部存储播放视频

    android - 用于编辑联系人的蜂窝同步适配器功能

    java - ArrayList.filter 不起作用

    android - Android通知不会弹出

    swift - 使用 MVVM 使用 RxSwift 查看初始数据源和过滤

    java - Android studio - Google 广告崩溃应用程序

    android - 如何从 ionic4 应用程序启动外部应用程序

    wpf - 在不破坏 MVVM 的情况下获取 XAML View 元素

    c# - 使用 MVVM 管理多项选择