1

I'm learning Kotlin Coroutines and I'm trying to build a simple app with some API requests. Unfortunately I've stumbled upon an error which is not really talkative, this is all I have in the logs:

FATAL EXCEPTION: main 
Process: com.tests.myapp, PID: 14743

This is my simple coroutine which would simply call an API endpoint. I've copied the syntax from this tutorial.

  CoroutineScope(Dispatchers.Main).launch {
       API.call().registration();
  }

For Kotlin Coroutines I use this version:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'

And for the networking library I have Retrofit like this:

object API {

    private const val BASE_URL = "http://my-test-url-comes-here.com"

    private val okHttpClient = OkHttpClient()
        .newBuilder()
        .addInterceptor(RequestInterceptor)
        .build()

    private fun getClient(): Retrofit =
        Retrofit.Builder()
            .client(okHttpClient)
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()


    fun call(): Endpoints {
      return  getClient().create(Endpoints::class.java)
    }
}

Any insights?

4
  • try/catch inside launch and log the exception Commented Feb 13, 2023 at 18:29
  • 1
    Hey @Adam Varhegyi! What does your Endpoints.kt file look like? Commented Feb 13, 2023 at 18:48
  • 1
    There are a couple of errors in that tutorial’s explanation of coroutines. Not a good source for learning them. 1) In practice, you would never create a CoroutineScope and leave it for dead after launching a coroutine with it. The only reason to create a CoroutineScope instead of using an existing one is so you can specifically manage its lifecycle. 2) You don’t need to defensively use withContext(Dispatchers.IO) everywhere. In their example, the function fetches a lot of data but doesn’t process it. It’s trivial to pass some references around, even if the reference is to a large object. Commented Feb 13, 2023 at 19:02
  • So no need to introduce unnecessary thread switching, complicating the code and slowing things down. If you were processing a lot of the data, Dispatchers.Default would be more appropriate, provided you provide adequate yielding in the code. Commented Feb 13, 2023 at 19:04

2 Answers 2

1

I think you should use Dispatchers.IO because you are calling a functon that uses network. by passing Dispatcher.Main, you are asking coroutinScope to use UI thread. that gives a Network on Main thread Exception. so,

  CoroutineScope(Dispatchers.IO /* replace Main with IO here */).launch {
       API.call().registration();
  }
Sign up to request clarification or add additional context in comments.

1 Comment

This is incorrect if the network function is a suspend function. A suspend function must never block. If it contains blocking code, it must internally specify a dispatcher with withContext.
0

try to use Dispatchers.IO and also I would suggest you to create your api service only once like this and check you manifest file - you should add internet permission to your app, to make network calls

object API {

   private const val BASE_URL = "http://my-test-url-comes-here.com"

   private val okHttpClient = OkHttpClient()
      .newBuilder()
      .addInterceptor(RequestInterceptor)
      .build()

   private val client by lazy {
      Retrofit.Builder()
          .client(okHttpClient)
          .baseUrl(BASE_URL)
          .addConverterFactory(GsonConverterFactory.create())
          .build()
   }


    val api by lazy {
       client.create(Endpoints::class.java)
    }

}

NOTE: the lazy initializer I wrote here is just sample you can also you non-lazy initializer

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.