Значение итератора не определено при первом запуске - PullRequest
1 голос
/ 12 июля 2020

В моем onViewCreated() внутри MythFragment я выполняю следующие шаги.

  1. Предварительно заполнить базу данных комнаты.
  2. Получить все записи из базы данных в MutableLiveData<List<..>>
  3. Инициализировать итератор для этих данных
  4. Нажмите кнопку «Далее», чтобы проверить условие 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()
            }
        }
    }
}

Я считаю, что проблема может быть в параллелизме (сопрограммы), но я не понимаю, что делаю не так.

1 Ответ

2 голосов
/ 13 июля 2020

Поскольку обе функции populateMyths() и fetchFromDatabase() запускают новые сопрограммы, обе эти сопрограммы будут работать параллельно. Таким образом, при первом вызове fetchFromDatabase() он может получать данные до того, как dao.insertAll() произошло в populateMyths(). Может быть, вам стоит переосмыслить / уточнить, чего вы стремитесь достичь sh, запустив эти сопрограммы.

...