'Kotlin: try catch in CoroutineScope still crash the app
I'm using the code below for a network request throught okhttp3:
runOnDefaultDispatcher {
try {
val newsResponse = Xxxx.xxxxClient.getNews()
if (newsResponse.success && newsResponse.data != null && newsResponse.data.count() > 0) {
runOnMainDispatcher {
val adapter = NewsAdapter(newsResponse.data, getString(R.string.news)).also {
initListener(it, newsResponse.data)
}
binding.list.adapter = adapter
adapter.notifyDataSetChanged()
}
}
} catch (exception: Exception) {
runOnMainDispatcher {
binding.list.visibility = View.GONE
val errorLayout = view.findViewById<RelativeLayout>(R.id.error_layout)
errorLayout.visibility = View.VISIBLE
errorLayout.findViewById<TextView>(R.id.error_title).text = "Oops..."
errorLayout.findViewById<TextView>(R.id.error_message).text = exception.message
}
}
}
The implementation code of runOnDefaultDispatcher
and runOnMainDispatcher
is down below:
import kotlinx.coroutines.*
fun block(block: suspend CoroutineScope.() -> Unit): suspend CoroutineScope.() -> Unit {
return block
}
fun runOnDefaultDispatcher(block: suspend CoroutineScope.() -> Unit) =
GlobalScope.launch(Dispatchers.Default, block = block)
suspend fun <T> onDefaultDispatcher(block: suspend CoroutineScope.() -> T) =
withContext(Dispatchers.Default, block = block)
fun runOnIoDispatcher(block: suspend CoroutineScope.() -> Unit) =
GlobalScope.launch(Dispatchers.IO, block = block)
suspend fun <T> onIoDispatcher(block: suspend CoroutineScope.() -> T) =
withContext(Dispatchers.IO, block = block)
fun runOnMainDispatcher(block: suspend CoroutineScope.() -> Unit) =
GlobalScope.launch(Dispatchers.Main.immediate, block = block)
suspend fun <T> onMainDispatcher(block: suspend CoroutineScope.() -> T) =
withContext(Dispatchers.Main.immediate, block = block)
I except the exception would be caught and no crash would appear.
However the application still CRASH:
FATAL EXCEPTION: DefaultDispatcher-worker-2
Java.net.SocketException: Connection reset
Solution 1:[1]
The calls to launch
don't work well with try/catch
.
e.g. this will crash the app
try {
GlobalScope.launch { throw Excepton() }
} catch (e: Exception) {
}
On the other hand, suspend
functions work with try/catch
as you would expect so this example DOES NOT crash the app:
suspend fun bang(): Unit = throw Exception()
try {
bang()
} catch (e: Exception) {
}
In your code you have launch
inside try/catch
, meaning you have a scenario like the first example here.
The solution is to build your program as suspend functions, and only use launch
one to execute the result (note: this doesn't apply universally but does apply in this scenario).
When running the program you probably want to use lifecycleScope
.
Also you might want to consider using a ViewModel
so that the network call survives configuration changes.
You can check the Kotlin Coroutines on Android guide for more.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | LordRaydenMK |