1

I need to do the next:

  1. Check is exist profile
  2. If exist then start async http request (getAdvertising()) by Retrofit lib
  3. if not exist then first loading profile from remote (by Retrofit) AND if success get result then start async http request (getAdvertising())

I do this by callback like this:

    fun getAdvertising(callback: Callback<List<Advertising>>) {
        val call = myRestClient.advertising
        executeAsync(call, callback)
    }

  private fun <T> executeAsync(call: Call<T>, callback: Callback<T>) {
        val currentApplicationProfileResponse = foService.applicationProfileResponse
        if (currentApplicationProfileResponse == null) {
            getApplicationProfile(object : DefaultRestClientCallback<ApplicationProfileResponse>() {

                override fun onTransportResponse(transportResponse: TransportResponse) {
                    super.onTransportResponse(transportResponse)
                    if (transportResponse.isSuccessful) {
                        //asynchronously
                        call.enqueue(callback)
                    } else { // not success
                        if (callback is DefaultRestClientCallback<*>) {
                            callback.onTransportResponse(transportResponse)
                        } else {
                            callback.onResponse(call, transportResponse.originalResponse as Response<T>?)
                        }
                    }
                }
            })
        } else { // appProfile is not null
            //asynchronously
            call.enqueue(callback)
        }
    }

Nice it's work fine.

But is to much code. Is it possible to repalace Callback by Kotlin's coroutines?

Alexei
  • 14,350
  • 37
  • 121
  • 240
  • 1
    Retrofit has support now for coroutines: https://proandroiddev.com/suspend-what-youre-doing-retrofit-has-now-coroutines-support-c65bd09ba067 – Alex Hart Jul 29 '19 at 12:47
  • 1
    You should use Retrofit 2.6.0 it now supports coroutines or you can do this https://stackoverflow.com/questions/48552925/existing-3-function-callback-to-kotlin-coroutines/48562175#48562175 – m3g4tr0n Jul 29 '19 at 13:17

3 Answers3

3
private fun getADvertise(onResult: (ArrayList<String>) -> Unit = {}) {
    CoroutineScope(Dispatchers.IO).launch {
        //Do Request To get Data using retrofit
        val result = ArrayList<String>()//result from retrofit
        withContext(Dispatchers.Main)
        {
            onResult(result)
        }

    }
}

private fun isProfileExist(): Boolean {
    //true or false
    return true
}

private fun getProfilePicture(id: String, OnResult: (String) -> Unit = {}) {
    CoroutineScope(Dispatchers.IO).launch {
        //Do Request To get Data using retrofit
        val result = "Link"//result from retrofit
        withContext(Dispatchers.Main)
        {
            OnResult(result)
        }

    }
}

//---------your main function------------------>
public fun execute(onResultMain: (ArrayList<String>) -> Unit = {}) {
    val exist = isProfileExist()
    if (exist) {
        getADvertise(onResultMain)
    } else {
        getProfilePicture("id") {

            getADvertise(onResultMain)
        }
    }

}
//onResultMain -> call back used to get result when they are ready ;) 
2

Use call.execute() ( i.e, synchronous retrofit request ) inside suspend function of coroutine.

 suspend fun <T> executeAsync(call: Call<T>, callback: Callback<T>) {
       try {
           if(foService.applicationProfileResponse != null) {
              if(T is List<Advertising>) {
                 val advertisings = call.execute() // synchronous call 
              } 
           }
       } catch(e : Exception) {
           // handle exception
       } 
 }

Or, add

   .addCallAdapterFactory(CoroutineCallAdapterFactory())

to retrofit builder and use .await() with deferred

    call.await() // call is of type deferred 
Santanu Sur
  • 10,997
  • 7
  • 33
  • 52
1

you can use this way

suspend fun <T> Call<T>.getResult(): T = suspendCoroutine { cont ->
    enqueue(object : Callback<T> {
        override fun onFailure(call: Call<T>, t: Throwable) {
            cont.resumeWithException(t)
        }

        override fun onResponse(call: Call<T>, response: Response<T>) {
            if (response.isSuccessful) {
                cont.resume(response.body()!!)
            } else {
                cont.resumeWithException(ErrorResponse(response.message(), response.code()))
            }
        }

    })
}
class ErrorResponse(message: String, code: Int) : Throwable(message )
Liam
  • 27,717
  • 28
  • 128
  • 190