如何用Kotlin的协程替换回调

时间:2019-07-29 12:41:20

标签: android retrofit2 kotlin-coroutines

我需要做下一个:

  1. 检查是否存在配置文件
  2. 如果存在,则通过Retrofit lib开始启动异步http请求(getAdvertising()
  3. 如果不存在,则首先从远程(通过翻新)加载配置文件,如果成功获得结果,则启动异步http请求(getAdvertising()

我通过这样的回调来做到这一点:

    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)
        }
    }

很好,工作正常。

但是要很多代码。是否有可能通过Kotlin的协程重新控制Callback?

3 个答案:

答案 0 :(得分:2)

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 ;) 

答案 1 :(得分:1)

在协同程序中使用call.execute()(即同步改造请求内部 suspend功能。

 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
       } 
 }

或者, 添加

   .addCallAdapterFactory(CoroutineCallAdapterFactory())

改造制造商并将.await()deferred一起使用

    call.await() // call is of type deferred 

答案 2 :(得分:0)

您可以使用这种方式

    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 )```