Solution 1 :
As both functions populateMyths()
and fetchFromDatabase()
are launching new coroutines, both these coroutines will run in parallel. So the first time fetchFromDatabase()
is called, it may be retrieving the data before dao.insertAll()
has happened in populateMyths()
.
Maybe you should rethink / clarify what you aim to accomplish by launching these coroutines.
Problem :
In my onViewCreated()
inside my MythFragment
I do these steps.
- Prepopulate Room database.
- Fetch all records from database into
MutableLiveData<List<..>>
- Initialize an iterator to these data
- Click the “Next” button an check condition
it.hasNext() == true
For some reason, only during the first run of the program, the it.hasNext()
gives me false
. I would expect it to be true, since the steps 1-3 should’ve already ensured, that the list is filled and the iterator points to the first element.
Interestingly, any later navigation on the MythView
retrieves the element correctly and it.hasNext()
gives me 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)
[email protected]
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()
}
}
}
}
I believe the problem might be in the concurrency (Coroutines), but I don’t understand what am I doing wrong.
Comments
Comment posted by herman
I don’t know yet what may be causing this, but is there any particular reason you are using
Comment posted by herman
BTW you probably don’t even need to use
Comment posted by discuss.kotlinlang.org/t/let-vs-if-not-null/3542
@herman I am just following the practises from a tutorial. Also, I reckoned there is some advatage in
Comment posted by herman
If you check
Comment posted by Slazer
I need to prepopulate my database in
Comment posted by herman
@Slazer what the best place to init DB is, is kindof another question. (can’t help you there). But the thing is, it seems you want to run both methods sequentially. Instead of putting a