val dates: LiveData<Dates> = liveData {
Toast.makeText(appl, "Parsing files now", Toast.LENGTH_SHORT).show()
val value = loadDatesFromFile()
emit(value)
}
private fun loadDatesFromFile(): Dates {
Files.readAllLines(path).forEach {
...
}
...
return dates
}
This code doesn’t work properly yet because loadDatesFromFile() runs on Dispatchers.Main instead of Dispatchers.IO. Android Studio rightfully complains about an inappropriate blocking method call:
There are several ways and combinations of CouroutineScope, withContext, launch, etc. that I could use to run the body of loadDatesFromFile() on Dispatchers.IO.
I’m fairly new to Kotlin, so my question is, what would be the most succinct and idiomatic way to do this?
That would launch readAllLines() asynchronously and OP clearly need to return the value synchronously. Also, if you create CoroutineScope() and then launch something with it, you should also remember to cancel it or otherwise it may leak background tasks and memory.
@AndreKR Use withContext(Dispatchers.IO) - this is the standard way of “jumping” to another thread. Just note you can’t emit() from a different thread using this technique. But using it in loadDatesFromFile() is fine.
AFAIK, you can safely suppress this warning. I don’t know why IntelliJ does not recognize such simple cases as a valid use of a blocking call. I believe (but I may be wrong) that in the past it didn’t show warnings when directly inside withContext(Dispatchers.IO).
Anyway, you can check it by yourself. Just put Thread.sleep() inside loadDatesFromFile(). Without withContext() it should block the UI. With it there shouldn’t be a problem.