try-catch in kotlin coroutine with withContext method

Viewed 1358

I found some documentation arguing about exception handling in Kotlin's coroutines with launch and async. But I could not found the solution dealing with the withContext.

suppose I have a coroutine like:

fun bar(path: String) {
    viewModelScope.launch {
        val foo = withContext(Dispatchers.IO) {
             foo(path)
        }
    }
}

fun foo(path: String) {
    // do something...
    val media = MediaMetadataRetriever()
    media.setDataSource(path)  // may throw IllegalArgumentException according to API's doc
    return media.frameAtTime
}

viewModelScope is imported from the lifecycle-viewmodel-ktx's implementation using a SupervisorJob.

Where should I put a try-catch block to deal with the IOException here?

1 Answers

try-catch in Kotlin coroutines feels a little clumsy, but I think it's partially because the designers of Kotlin don't think you should be using it in the first place. When something is a checked exception (caused by something outside the programmer's control), their recommendation is to wrap it or return null. For example:

fun foo(path: String): Bitmap? {
    // do something...
    val media = MediaMetadataRetriever()
    try {
        media.setDataSource(path)
    catch (e: IOException) {
        Log.e(TAG, "Failed to set media data source", e)
        return null
    }
    return media.frameAtTime
}

fun bar(path: String) {
    viewModelScope.launch {
        val foo = withContext(Dispatchers.IO) {
             foo(path)
        }
        if (foo == null) {
            // show error to user or something
        } else {
           // do something with smart-cast non-null foo Bitmap
        }
    }
}

By the way, for a blocking function like foo that you will never call from the main thread, I suggest making it a suspend function and moving the withContext(Dispatchers.IO) into the function so it is self-contained and you can freely call it from any coroutine.

Related