Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 第一次运行时未定义迭代器值_Kotlin_Concurrency_Android Room_Kotlin Coroutines - Fatal编程技术网

Kotlin 第一次运行时未定义迭代器值

Kotlin 第一次运行时未定义迭代器值,kotlin,concurrency,android-room,kotlin-coroutines,Kotlin,Concurrency,Android Room,Kotlin Coroutines,在myonViewCreated()中的myMythFragment中,我执行以下步骤 预填充房间数据库 将数据库中的所有记录提取到MutableLiveData 初始化这些数据的迭代器 单击“下一步”按钮检查条件it.hasNext()==true 出于某种原因,只有在程序的第一次运行期间,it.hasNext()才会给出false。我希望这是真的,因为步骤1-3应该已经确保列表已填充,迭代器指向第一个元素 有趣的是,MythView上的任何后续导航都会正确地检索元素,并it.hasNext(

在my
onViewCreated()
中的my
MythFragment
中,我执行以下步骤

  • 预填充房间数据库
  • 将数据库中的所有记录提取到
    MutableLiveData
  • 初始化这些数据的迭代器
  • 单击“下一步”按钮检查条件
    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)
                    }
                }
            }
        }
    }
    
    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()
                }
            }
        }
    }
    
    MythViewModel.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)
                    }
                }
            }
        }
    }
    
    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()
                }
            }
        }
    }
    
    MythViewModel类(应用程序:应用程序):BaseViewModel(应用程序){ private val myths=MutableLiveData() lateinit var mythsIterator:迭代器 有趣的大众化{ 发射{ val dao=MythDatabase(getApplication()).mythDao() if(dao.getRowCount()>0) return@launch val mythList=arrayListOf( 神话(“这是神话1”,“这是对神话1的评价”), 神话(“这是神话2”,“这是对神话2的评价”), 神话(“这是神话3”,“这是对神话3的评价”), 神话(“这是神话4”,“这是对神话4的评价”), 神话(“这是神话5”,“这是对神话5的评价”) ) 达奥酒店( *mythList.toTypedArray() ) } } fun fetchFromDatabase(){ 发射{ val mythList=MythDatabase(getApplication()).mythDao().getAllMyths() myths.value=mythList 神话。价值?让我们{ mythsIterator=it.iterator() } } } }
    我相信问题可能出在并发(协程)上,但我不明白我做错了什么。

    由于两个函数
    populateMyths()
    fetchFromDatabase()
    都在启动新的协程,这两个协程将并行运行。因此,第一次调用
    fetchFromDatabase()
    时,它可能是在
    populateMyths()中发生的
    dao.insertAll()
    之前检索数据。
    也许你应该重新思考/澄清通过启动这些协同程序你的目标是什么。

    我还不知道是什么导致了这一点,但是你使用
    ?,有什么特别的原因吗。如果(mythList!=null){mythsIterator=mythList.iterator();}
    ,让
    代替
    ?。您是否尝试过在DB查找后在行上设置断点,或记录列表中的项目数?顺便说一句,您甚至不需要使用
    lateinit var
    ,而只需要使用一个计算属性:
    val mythsIterator get()=myths.value.iterator()
    。每次调用getter时,它都会被调用并返回一个新的迭代器,这可能会更好,因为否则您只能迭代一次。@herman我只是按照教程中的练习进行操作。另外,我认为
    中有一些建议。让
    处理“变异属性”(mutating properties)()。我不知道那是什么,但安全总比后悔好。我对调试不是很熟悉,我觉得太难了。我可以试一试。如果你检查
    mythList
    是否为空,这是100%安全的,因为它是1)一个val,所以不能变异;2)局部,所以即使它是一个var,也不能在这个函数之外变异。如果不能保证空安全性(例如如果使用一个可以从此函数外部变异的字段),那么Kotlin不会让代码编译(不添加
    !!
    )。在任何情况下,将单个迭代器保留为只能迭代一次的属性似乎都不正确。应用程序启动后,我需要在
    populateMyths()
    中预填充数据库。因此,将此函数放入MythFragment.onViewCreated()中可能不是一个好主意。我必须确保在从
    MythFragment
    调用
    fetchFromDatabase()
    之前已预填充数据库。为了实现这一点,我尝试将
    populateMyths()
    移动到
    onCreate()
    ,但仍然没有很快填充。我应该从MainActivity还是MainFragment中调用它?这是一个好的设计决策吗?@Slazer初始化数据库的最佳位置是什么,这是另一个问题。(我帮不了你)。但问题是,您似乎希望按顺序运行这两种方法。不要在每个方法中放置
    launch
    块,而是尝试删除它们,并在对这两个方法的调用周围添加一个
    launch
    块?