我正在尝试按此顺序完成这些步骤。
执行后,我按此顺序获得 Toasts
我期望的是相同数量的元素。是否因为协程而有所不同?我必须使用 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.ktclass 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.ktabstract 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/