You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin重写的onSuccess函数中返回列表?

解决异步请求中返回数据的问题

你遇到的核心问题是网络请求是异步操作——clientInitialization函数发起请求后会立刻执行完毕,而onSuccess方法要等网络请求完成后才会被调用,所以没法直接从onSuccess里返回列表,必须用异步的方式传递结果。下面给你两种常用的解决方案:

方案一:自定义回调接口

这是处理异步回调的传统方式,通过定义一个接口来传递请求结果:

1. 定义回调接口

// 定义回调接口,用于传递成功/失败的结果
interface MovieInfoCallback {
    fun onSuccess(movieInfo: List<String>)
    fun onFailure(errorMessage: String)
}

2. 修改原函数,加入回调参数

把movieInfoList的创建移到onSuccess里,请求完成后通过回调接口传递结果:

private fun clientInitialization(
    client: AsyncHttpClient,
    index: Int,
    movieAttributes: List<String>,
    callback: MovieInfoCallback
) {
    client["https://api.themoviedb.org/3/trending/movie/week?api_key=xxxxxx", object : JsonHttpResponseHandler() {
        override fun onSuccess(statusCode: Int, headers: Headers, json: JsonHttpResponseHandler.JSON) {
            val movieInfoList = mutableListOf<String>()
            val resultsArray = json.jsonObject.getJSONArray("results")
            val arrayLength = resultsArray.length()

            if (index < arrayLength) {
                // 提前获取指定索引的电影对象,避免重复调用getJSONArray
                val movieObject = resultsArray.getJSONObject(index)
                for (item in movieAttributes) {
                    val currentAttribute = movieObject.getString(item)
                    movieInfoList.add(currentAttribute)
                }
            }
            // 请求成功,通过回调返回结果
            callback.onSuccess(movieInfoList)
        }

        override fun onFailure(statusCode: Int, headers: Headers?, errorResponse: String, throwable: Throwable?) {
            Log.d("Pic error", errorResponse)
            // 请求失败,传递错误信息
            callback.onFailure(errorResponse)
        }
    }]
}

3. 调用函数时处理结果

// 调用示例,传入回调处理结果
clientInitialization(
    client = yourAsyncHttpClientInstance,
    index = 0,
    movieAttributes = listOf("title", "release_date", "overview"),
    callback = object : MovieInfoCallback {
        override fun onSuccess(movieInfo: List<String>) {
            // 在这里拿到填充好的movieInfoList,做后续处理(比如更新UI)
        }

        override fun onFailure(errorMessage: String) {
            // 处理请求失败的情况
        }
    }
)

方案二:使用Kotlin协程(推荐)

Kotlin协程可以让你用同步的写法处理异步逻辑,代码更简洁易读,是现代Android开发的推荐方式:

1. 将函数改为挂起函数

用suspendCoroutine把异步回调包装成挂起函数,这样可以直接返回结果:

// 注意添加suspend关键字,把函数变成挂起函数
private suspend fun clientInitialization(
    client: AsyncHttpClient,
    index: Int,
    movieAttributes: List<String>
): List<String> = suspendCoroutine { continuation ->
    client["https://api.themoviedb.org/3/trending/movie/week?api_key=xxxxxx", object : JsonHttpResponseHandler() {
        override fun onSuccess(statusCode: Int, headers: Headers, json: JsonHttpResponseHandler.JSON) {
            val movieInfoList = mutableListOf<String>()
            val resultsArray = json.jsonObject.getJSONArray("results")
            val arrayLength = resultsArray.length()

            if (index < arrayLength) {
                val movieObject = resultsArray.getJSONObject(index)
                for (item in movieAttributes) {
                    val currentAttribute = movieObject.getString(item)
                    movieInfoList.add(currentAttribute)
                }
            }
            // 恢复协程,返回结果
            continuation.resume(movieInfoList)
        }

        override fun onFailure(statusCode: Int, headers: Headers?, errorResponse: String, throwable: Throwable?) {
            Log.d("Pic error", errorResponse)
            // 恢复协程并抛出异常,方便上层捕获
            val exception = throwable ?: Exception(errorResponse)
            continuation.resumeWithException(exception)
        }
    }]
}

2. 在协程作用域中调用函数

协程必须在协程作用域内执行,比如在Activity/Fragment中可以用lifecycleScope,通用场景用CoroutineScope:

// 示例:在Activity中调用(需要依赖androidx.lifecycle:lifecycle-runtime-ktx)
lifecycleScope.launch {
    try {
        val movieInfo = clientInitialization(
            client = yourAsyncHttpClientInstance,
            index = 0,
            movieAttributes = listOf("title", "release_date")
        )
        // 在这里拿到结果,处理逻辑(比如更新UI)
    } catch (e: Exception) {
        // 捕获请求失败的异常,处理错误
    }
}

// 通用场景调用
CoroutineScope(Dispatchers.IO).launch {
    try {
        val movieInfo = clientInitialization(...)
        // 如果需要更新UI,切换到主线程
        withContext(Dispatchers.Main) {
            // 更新UI逻辑
        }
    } catch (e: Exception) {
        // 处理错误
    }
}

额外优化建议

  • 不要硬编码API Key,建议放到strings.xml或者local.properties中,通过配置读取,避免泄露。
  • 提取JSON解析逻辑到单独的函数,让代码更清晰。
  • 注意空安全:比如调用getString时,如果字段可能不存在,可以用optString避免崩溃。

内容的提问来源于stack exchange,提问作者Lyton_Spurz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 05:45:07