Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android and Kotlin coroutines: inappropriate blocking method call

I have the following class:

class Repository(
    private val assetManager: AssetManager,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) {
    suspend fun fetchHeritagesList(): HeritageResponse = withContext(ioDispatcher) {
        try {
            // TODO Blocking method call?
            val bufferReader = assetManager.open("heritages.json").bufferedReader()
...

and I'm wondering why do I get a warning in the open("heritages.json") saying Innapropriate blocking method call? isn't the withContext(ioDispatcher) fixing that?

Thanks for the explanation!

like image 600
noloman Avatar asked Jan 10 '20 14:01

noloman


People also ask

What is the use of delay in Kotlin coroutine?

Kotlin Coroutines on Android Suspend Function In Kotlin Coroutines As it is known that when the user calls the delay () function in any coroutine, it will not block the thread in which it is running, while the delay () function is called one can do some other operations like updating UI and many more things.

How do I know if a kotlinx coroutine is cancelled?

One way to check for cancellation is by calling the ensureActive function. All suspend functions from kotlinx.coroutines such as withContext and delay are cancellable. If your coroutine calls them, you shouldn't need to do any additional work.

What are coroutines in Kotlin?

Coroutines were added to Kotlin in version 1.3 and are based on established concepts from other languages. On Android, coroutines help to manage long-running tasks that might otherwise block the main thread and cause your app to become unresponsive. Over 50% of professional developers who use coroutines have reported seeing increased productivity.

What is the difference between delay () and suspend () in Kotlin?

Suspend Function In Kotlin Coroutines As it is known that when the user calls the delay () function in any coroutine, it will not block the thread in which it is running, while the delay () function is called one can do some other operations like updating UI and many more things.


1 Answers

IntelliJ inspection that looks for blocking calls inside suspendable functions isn't powerful enough to see through a level of indirection between Dispatchers.IO and its usage in withContext. Here's a minimal reproducer of the issue:

class IoTest {
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO

    suspend fun indirectRef() = withContext(ioDispatcher) {
        FileInputStream(File("dummy.txt")) // Flagged as inappropriate blocking call
    }

    suspend fun directRef() = withContext(Dispatchers.IO) {
        FileInputStream(File("dummy.txt")) // Not flagged
    }
}

However, unlike in my case, your ioDispatcher is exposed for injection through the constructor so you could just as easily supply Dispatchers.Main instead of it, and that would constitute inappropriate blocking.

Unfortunately I haven't yet heard of any way to formally specify the contract of a dispatcher as "tolerating blocking calls", so that you could enforce it in the constructor.

There is already a similar issue open on YouTrack.

EDIT: As of the build from March 16, 2022, there seems to be a regression that flags IO calls even inside a withContext(IO).

like image 147
Marko Topolnik Avatar answered Oct 08 '22 01:10

Marko Topolnik