DEV Community

Cover image for How to debug Kotlin coroutines in Android
Tristan Elliott
Tristan Elliott

Posted on

How to debug Kotlin coroutines in Android

Table of contents

  1. The Problem
  2. Step 1: Create function
  3. Step 2: Enable debugging
  4. Step 3: improve debugger

The code

My app on the Google play store

Resources

  • All the information from this post was found inside the book: Kotlin coroutines by tutorials, authored by, Filip Babic, Nishant Srivastava, Luka Kordić

The problem

  • So I am currently in the process of moving all of my remote requests off the main dispatcher and onto the I.O dispatcher(which is a best practice). However, I thought it might be nice for me to be able to visualize which coroutines are running and when. So here is how to create a simple coroutine logger for debugging

Step 1: creating the logging function

fun logCoroutineInfo(tag:String,msg:String){
    Log.d(tag,"Running on: [${Thread.currentThread().name}] | $msg")
}
logCoroutineInfo("CoroutineDebugging","Fetching from remote")

Enter fullscreen mode Exit fullscreen mode
  • Notice how the code above uses Log.d(), this is so it will work with Android's built in LogCat. Now if we run use this function inside of our request code we will get something like this: Running on: [main] | Fetching from remote and lets be honest, that's not very helpful. We MUST SPEAK THE MAGIC WORDS TO ENABLE COROUTINE DEBUGGING!!!!!!!

Step 2: enable debugging(speak the magic words)

  • Now kotlin.coroutines includes debugging facilities, but it needs to be enabled by setting the -Dkotlinx.coroutines.debug to on as a JVM property. We can do this inside the MainActivity class's onCreate() function, like so:
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      System.setProperty("kotlinx.coroutines.debug", if(BuildConfig.DEBUG) "on" else "off")

   }
}

Enter fullscreen mode Exit fullscreen mode
  • Now when we run the logCoroutineInfo("CoroutineDebugging","Fetching from remote") function we will get a response like this: Running on: [main @coroutine#6] | Fetching from remote

-This is because in debug mode, every coroutines is assigned a unique consecutive identifier. Every thread that executes a coroutine has its name modifier to include the name and the identifier of the currently running coroutine.

Step 3: Improving the debugger

  • We can do one more step to improve the debugger. We can explicitly name our coroutine. Naming our coroutine just makes the logs easier to consume and more focused and we can do so with withContext{}:
viewModelScope.launch{
  withContext( Dispatchers.IO + CoroutineName("TokenValidator")){
     //remote work done inside of here
    logCoroutineInfo("CoroutineDebugging","Fetching from remote")

  }
}

Enter fullscreen mode Exit fullscreen mode
  • The output of logCoroutinesInfo is now, [DefaultDispatcher-worker-1 @TokenValidator#40] | Fetching from remote. Which is a lot more explicit.

  • NOW GO FORTH AND DEBUG!!!!!

Conclusion

  • Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.

Top comments (0)