【发布时间】:2020-11-02 01:58:59
【问题描述】:
在我的onViewCreated() 里面我的MythFragment 我执行这些步骤。
- 预填充 Room 数据库。
- 从数据库中获取所有记录到
MutableLiveData<List<..>> - 初始化这些数据的迭代器
- 单击“下一步”按钮检查条件
it.hasNext() == true
由于某种原因,仅在程序的第一次运行期间,it.hasNext() 给了我false。我希望这是真的,因为步骤 1-3 应该已经确保列表已填充并且迭代器指向第一个元素。
有趣的是,MythView 上的任何后续导航都会正确检索元素,it.hasNext() 给我true。
MythFragment.kt
class MythFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProviders.of(this).get(MythViewModel::class.java)
viewModel.populateMyths()
viewModel.fetchFromDatabase()
buttonNextMyth.setOnClickListener {
mythEvaluation.visibility = View.GONE
buttonIsThisMythTruthful.visibility = View.VISIBLE
viewModel.mythsIterator.let {
if (it.hasNext()) {
val myth = it.next()
mythText.text = myth.myth
mythEvaluation.text = myth.evaluation
} else {
Toast.makeText(activity, "There is no myth, because it.hasNext() is false!)", Toast.LENGTH_SHORT).show()
val action = MythFragmentDirections.actionMenuFragment()
Navigation.findNavController(view).navigate(action)
}
}
}
}
}
MythViewModel.kt
class MythViewModel(application: Application) : BaseViewModel(application) {
private val myths = MutableLiveData<List<Myth>>()
lateinit var mythsIterator: Iterator<Myth>
fun populateMyths() {
launch {
val dao = MythDatabase(getApplication()).mythDao()
if (dao.getRowCount() > 0)
return@launch
val mythList = arrayListOf(
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 {
val mythList = MythDatabase(getApplication()).mythDao().getAllMyths()
myths.value = mythList
myths.value?.let {
mythsIterator = it.iterator()
}
}
}
}
我认为问题可能出在并发(协程)上,但我不明白我做错了什么。
【问题讨论】:
-
我还不知道是什么原因造成的,但是您使用
?.let而不是if (mythList != null) { mythsIterator = mythList.iterator(); }有什么特别的原因吗?您是否尝试过在数据库查找后在行上设置断点,或者记录列表中的项目数? -
顺便说一句,您可能甚至不需要使用
lateinit var,而只需使用计算属性:val mythsIterator get() = myths.value.iterator()。每次调用时都会调用 getter 并返回一个新的迭代器,这可能会更好,因为否则你只能迭代一次。 -
@herman 我只是按照教程中的做法。此外,我认为
?.let有一些优势,因为它适用于“变异属性”(discuss.kotlinlang.org/t/let-vs-if-not-null/3542)。我不确定那是什么,但安全总比抱歉好。我对调试不是很熟悉,我认为这太难了。我可以试试看。 -
如果你检查
mythList是否为空,那是 100% 安全的,因为它是 1) 一个 val,所以不能被变异,2) 本地,所以即使它是一个 var,它也不能t 在此函数之外发生变异。如果不能保证 null 安全性(例如,如果使用可以从该函数外部改变的字段),那么 Kotlin 不会让代码编译(不添加!!)。在任何情况下,将单个迭代器保留为只能迭代一次的属性似乎并不正确。
标签: kotlin concurrency android-room kotlin-coroutines