【问题标题】:How to return response body from function with retrofit and kotlin?如何使用改造和 kotlin 从函数返回响应体?
【发布时间】:2021-11-21 06:37:28
【问题描述】:

这是我的代码:

fun getRandomComputerDetails(context: Context) {
    if (isNetworkAvailable(context)) {
        val retrofit: Retrofit = Retrofit.Builder()
            .baseUrl(BuildConfig.API_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        val service: RandomComputerApiService =
            retrofit.create(RandomComputerApiService::class.java)

        val listCall: Call<RandomComputerApiResponse> = service.getRandomComputer()

        listCall.enqueue(object : Callback<RandomComputerApiResponse> {
            override fun onResponse(
                call: Call<RandomComputerApiResponse>,
                response: Response<RandomComputerApiResponse>
            ) {
                if (response.isSuccessful) {
                    val randomComputerList: RandomComputerApiResponse? = response.body()
                    if (randomComputerList != null) {
                        // TODO how to return randomComputerList?
                    }
                    Log.i("Response result", "$randomComputerList")
                } else {
                    when (response.code()) {
                        400 -> {
                            errorDialogHandler(context, R.string.dialog_error_400)
                            Log.e("Error 400", "Bad Connection")
                        }
                        404 -> {
                            errorDialogHandler(context, R.string.dialog_error_404)
                            Log.e("Error 404", "Not Found")
                        }
                        500 -> {
                            errorDialogHandler(context, R.string.dialog_error_500)
                            Log.e("Error 500", "Server Error")
                        }
                        else -> {
                            errorDialogHandler(context, R.string.dialog_error_generic_error)
                            Log.e("Error", "Generic Error")
                        }
                    }
                }
            }

            override fun onFailure(call: Call<RandomComputerApiResponse>, t: Throwable) {
                Log.e("Response error", t.message.toString())
            }
        })
    } else {
        // NO INTERNET CONNECTION
        errorDialogHandler(context, R.string.dialog_error_no_internet_connection)
    }
}

如何返回我的randomComputerList 正文以便在片段中使用它?我正在使用retrofit2,我的想法是在特定文件中分离负责执行API调用逻辑的函数,然后在片段中调用它。

【问题讨论】:

  • 这段代码到底是在哪里写的?在片段中,视图模型?
  • 一个简单的 kotlin 文件,在一个单独的文件夹中。我做错了吗?我仍然没有改造经验,但我想简化代码并且不想将所有内容放在一个文件中。所以我不知道如何从函数中获取响应体

标签: android kotlin retrofit retrofit2


【解决方案1】:

您可以创建接口并通过它返回结果例如我创建了一个ResultListener接口

interface ResultListener<S> {
    fun onSuccess(successModel: S)
    fun onFail(any: String?)
    fun onError(e: Throwable?)
}

response.isSuccessful 上使用resultListener.onSuccess(randomComputerList) 传递接口并从接口获取结果

fun getRandomComputerDetails(context: Context, resultListener: ResultListener<RandomComputerApiResponse>) {
    if (isNetworkAvailable(context)) {
        val retrofit: Retrofit = Retrofit.Builder()
            .baseUrl(BuildConfig.API_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        val service: RandomComputerApiService =
            retrofit.create(RandomComputerApiService::class.java)

        val listCall: Call<RandomComputerApiResponse> = service.getRandomComputer()

        listCall.enqueue(object : Callback<RandomComputerApiResponse> {
            override fun onResponse(
                call: Call<RandomComputerApiResponse>,
                response: Response<RandomComputerApiResponse>
            ) {
                if (response.isSuccessful) {
                    val randomComputerList: RandomComputerApiResponse? = response.body()
                    if (randomComputerList != null) {
                        // TODO how to return randomComputerList?
                        resultListener.onSuccess(randomComputerList)
                    }
                    Log.i("Response result", "$randomComputerList")
                } else {
                    when (response.code()) {
                        400 -> {
                            errorDialogHandler(context, R.string.dialog_error_400)
                            Log.e("Error 400", "Bad Connection")
                        }
                        404 -> {
                            errorDialogHandler(context, R.string.dialog_error_404)
                            Log.e("Error 404", "Not Found")
                        }
                        500 -> {
                            errorDialogHandler(context, R.string.dialog_error_500)
                            Log.e("Error 500", "Server Error")
                        }
                        else -> {
                            errorDialogHandler(context, R.string.dialog_error_generic_error)
                            Log.e("Error", "Generic Error")
                        }
                    }
                }
            }

            override fun onFailure(call: Call<RandomComputerApiResponse>, t: Throwable) {
                Log.e("Response error", t.message.toString())
            }
        })
    } else {
        // NO INTERNET CONNECTION
        errorDialogHandler(context, R.string.dialog_error_no_internet_connection)
    }
}

这很有趣

getRandomComputerDetails(
    context = this,
    resultListener = object : ResultListener<RandomComputerApiResponse> {
        override fun onSuccess(successModel: RandomComputerApiResponse) {
            //handle success result
        }

        override fun onFail(any: String?) {
            //handle Fail result
        }

        override fun onError(e: Throwable?) {
            //handle Error
        }
    })

【讨论】:

  • 最好给 ResultListener 一个通用的返回类型,这样返回的值就不必强制转换为正确的类型。
  • 答案已更新,您可以在onSuccess 中传递successModel 中的任意一个
  • 你能给我一个例子吗,我如何在片段中使用和调用接口结果监听器?我对接口不熟悉
  • @Munir 我认为您需要在继续之前学习更多基础知识。接口是比进行网络调用更基本的概念。
  • @Munir 添加了如何调用 fun。
【解决方案2】:

回调接口的替代方法是使用协程。为此,请将其标记为挂起函数并使用await() 而不是enqueue()await() 调用必须包含在 try/catch 中以捕获失败条件(类似于 enqueue() 中的 onFailure)。而且我将无网络条件移到了开头,这样您就不必将所有代码嵌套在 if 块中。

suspend fun getRandomComputerDetails(context: Context): RandomComputerApiResponse? {
    if (!isNetworkAvailable(context)) {
        // NO INTERNET CONNECTION
        errorDialogHandler(context, R.string.dialog_error_no_internet_connection)
        return null
    }
    val retrofit: Retrofit = Retrofit.Builder()
        .baseUrl(BuildConfig.API_BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    val service: RandomComputerApiService =
        retrofit.create(RandomComputerApiService::class.java)

    val response = try { 
        service.getRandomComputer().await() 
    } catch (t: Throwable) {
        // code for failure condition
        // errorDialogHandler(context, R.string.???)
        Log.e("Response error", t.message.toString())
        return null
    }

    if (response.isSuccessful) {
        return response.body()
    }

    when (response.code()) {
        400 -> {
            errorDialogHandler(context, R.string.dialog_error_400)
            Log.e("Error 400", "Bad Connection")
        }
        404 -> {
            errorDialogHandler(context, R.string.dialog_error_404)
            Log.e("Error 404", "Not Found")
        }
        500 -> {
            errorDialogHandler(context, R.string.dialog_error_500)
            Log.e("Error 500", "Server Error")
        }
        else -> {
            errorDialogHandler(context, R.string.dialog_error_generic_error)
            Log.e("Error", "Generic Error")
        }
    }
    return null
}

然后在你的片段中:

lifecycleScope.launch {
    val response = getRandomComputerDetails(requireContext())
    if (response != null) {
        // Do something with response of type RandomComputerApiResponse
    }
}

【讨论】:

  • 绝对是一种更新的方法,因为它也摆脱了Call.enqueue 方法
猜你喜欢
  • 2017-01-15
  • 2021-02-24
  • 2022-01-01
  • 2022-01-08
  • 2019-05-09
  • 1970-01-01
  • 2019-06-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多