【问题标题】:Returning a value after callback in Kotlin在 Kotlin 中回调后返回一个值
【发布时间】:2020-01-30 01:01:06
【问题描述】:

在 kotlin 中回调后如何返回值,我尝试使用 Thread.sleep 但它不起作用

   fun searchColorFromAPI(): Colors {
    val service: RetrofitService = ServiceGenerator.createService(RetrofitService::class.java)
    val result: MutableList<String> = arrayListOf()
    val call: Call<Colors?>? = service.unityConverter(result)
    call?.enqueue(object : Callback<Colors?> {
        override fun onResponse(call: Call<Colors?>?, response: Response<Colors?>) {
            //switchProgressVisibility()
            if (response.isSuccessful) {
                val serviceResponse: Colors? = response.body()

                if (serviceResponse != null) {
                    mColors = serviceResponse

                }
                else {
                    //buildToast(getString(R.string.null_response))
                }
            }

            else {
                //buildToast(getString(R.string.response_unsuccessful))
                val errorBody: ResponseBody = response.errorBody()
                Log.e(TAG, errorBody.toString())
            }
        }

        override fun onFailure(call: Call<Colors?>?, t: Throwable?) {
           /* buildToast(getString(R.string.error_calling_service))
            Log.e(TAG, t?.message)*/
        }
    })

    return mColors
}

总是,mColors 在 onFailure 或 onResponse 之前返回,因为它们是异步的。在这段代码在 MainActivity 之前,但我被建议起飞,但现在当我尝试获取 mColors 时,我在执行 onResponse 之前和之后得到空值,请我还在学习 Kotlin 和 Android。

【问题讨论】:

标签: android kotlin


【解决方案1】:

您的问题源于Retrofitcallasynchronous,所以只要您调用searchColorFromAPI,它就会返回您mColors,但API 调用可能尚未进行,所以在 API 调用之前获得 mColors 值。

要解决这个问题,你可以这样做

  1. 使用callback这将需要对您当前的设置进行少量修改,但第二个选项比这个更可取。使用callback,您的函数应该看起来像这个。

    /* Now instead of returning a value, your function takes a function (named callback) 
       as parameter. when your api call finishes, you can call the callback function and 
       pass the api response.
     */
    fun searchColorFromAPI(callback: (Colors?) -> Unit) {
        val service: RetrofitService = ServiceGenerator.createService(RetrofitService::class.java)
        val result: MutableList<String> = arrayListOf()
        val call: Call<Colors?>? = service.unityConverter(result)
        call?.enqueue(object : Callback<Colors?> {
            override fun onResponse(call: Call<Colors?>?, response: Response<Colors?>) {
                //switchProgressVisibility()
                if (response.isSuccessful) {
                    val serviceResponse: Colors? = response.body()
                    /** pass API response to callback */
                    callback(serviceResponse)
                }
                else {
                    val errorBody: ResponseBody = response.errorBody()
                    Log.e(TAG, errorBody.toString())
                    callback(null)
                }
            }
    
            override fun onFailure(call: Call<Colors?>?, t: Throwable?) {
                callback(null)
            }
        })
    }
    

并在您的activity 中声明function,如下所示。

// This function will be called when your api call finishes
// and it will give you the api response
fun apiCallback(colors: Colors?){
      if(colors == null){
        // API Call failed
    }
    else{
        // use colors as returned by API
    }
}

现在调用searchColorFromApi 应该是这样的

searchColorFromApi(apiCallback)
  1. 使用Live Data,在viewmodel 中声明field,如果您不使用viewmodel,则在具有searchColorFromApi 函数的class 中声明它。

    var colors: MutableLiveData<Colors> = MutableLiveData()
    

并修改你的searchColorFromAPI函数如下

fun searchColorFromAPI() {
        val service: RetrofitService = ServiceGenerator.createService(RetrofitService::class.java)
        val result: MutableList<String> = arrayListOf()
        val call: Call<Colors?>? = service.unityConverter(result)
        call?.enqueue(object : Callback<Colors?> {
            override fun onResponse(call: Call<Colors?>?, response: Response<Colors?>) {
                //switchProgressVisibility()
                if (response.isSuccessful) {
                    val serviceResponse: Colors? = response.body()
                    if (serviceResponse != null) {
                       colors.postValue(response.body)
                    }
                }
                else {
                    colors.postValue(null)
                    val errorBody: ResponseBody = response.errorBody()
                    Log.e(TAG, errorBody.toString())
                }
            }

            override fun onFailure(call: Call<Colors?>?, t: Throwable?) {
                colors.postValue(null)
            }
        })
    }

并在您的activity 中关注

  fun setupObservers(){
       yourApiCallingClass.colors.observe(this, Observer {
        // this code is called when ever value of color field changes
       })
   }

【讨论】:

    【解决方案2】:
    1. 您可以使用实时数据,一旦回调接收到就会更新,调用者片段/活动会观察到相同的实时数据

    2. 您可以使用协程从其中包含异步调用的函数返回一个值。

    3. 您可以使用对活动/片段的接口回调来触发从改造调用接收到的更新。

    【讨论】:

    • 我同意您的回答,但您实际上并没有向 OP 展示如何执行这些操作,所以我认为它不会增加太多价值 :) 您应该考虑为每个示例添加简单的示例这些
    猜你喜欢
    • 1970-01-01
    • 2013-12-26
    • 1970-01-01
    • 2020-01-20
    • 1970-01-01
    • 2022-11-11
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多