Inappropriate blocking method call in liveData function

I want to parse some files into a LiveData.

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:

image

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?

You must declare a variable

private val ioScope = CoroutineScope(Dispatchers.IO)

and, then, you can use

ioScope.launch {
Files.readAllLines(path).forEach {

}
}

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.

Android Studio disagrees with you. :slight_smile:

I could just suppress the warning of course.

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.