Android Kotlin:API调用后fetchedTags为空,如何获取异步数据?
问题分析
你的问题核心在于API调用是异步操作——fetchTags()执行时,它不会阻塞主线程等待接口返回数据,而是立刻继续执行后面的println(fetchedTags[0].name),这时候接口请求还在后台跑,fetchedTags自然还是null,直接访问甚至会抛出空指针异常。
解决方案
下面给你几种适合Kotlin/Android的常见解决方式,按推荐程度排序:
1. 使用Kotlin协程(最推荐)
Kotlin协程让异步代码写起来像同步代码,非常简洁。你需要做这些修改:
- 给
fetchTags()加上suspend关键字,让它成为挂起函数 - 在
onCreate里用lifecycleScope.launch启动协程,确保在Activity生命周期内执行
修改后的代码示例:
class MainActivity : AppCompatActivity() { var fetchedTags: List<Tags>? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 用lifecycleScope启动协程,绑定Activity生命周期 lifecycleScope.launch { fetchTags() // 现在API请求已经完成,fetchedTags有数据了 fetchedTags?.let { println(it[0].name) fetchBooks() makeMapOutOfTagsAndBooks() } ?: run { // 处理接口请求失败的情况 println("Failed to fetch tags") } } } // 标记为挂起函数,内部用withContext切换到IO线程执行网络请求 private suspend fun fetchTags() { withContext(Dispatchers.IO) { // 这里写你的网络请求逻辑,比如用Retrofit或者OkHttp // 假设请求成功后给fetchedTags赋值 fetchedTags = apiService.getTags() } } }
2. 使用回调函数
如果暂时不想用协程,可以给fetchTags()加一个回调参数,当接口请求完成后触发回调:
class MainActivity : AppCompatActivity() { var fetchedTags: List<Tags>? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) fetchTags { tags -> fetchedTags = tags // 在回调里执行后续操作 println(tags[0].name) fetchBooks() makeMapOutOfTagsAndBooks() } } fun fetchTags(onSuccess: (List<Tags>) -> Unit) { // 这里写你的异步网络请求逻辑 // 比如用OkHttp的Callback: val request = Request.Builder().url("your-api-url").build() OkHttpClient().newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { // 处理请求失败 } override fun onResponse(call: Call, response: Response) { response.body?.let { // 解析返回的JSON为List<Tags> val tags = Gson().fromJson(it.string(), object : TypeToken<List<Tags>>() {}.type) // 切换回主线程更新UI或执行后续操作 runOnUiThread { onSuccess(tags) } } } }) } }
3. 使用LiveData(适合MVVM架构)
如果你用MVVM模式,可以把fetchedTags改成LiveData,观察它的变化来执行后续操作:
class MainActivity : AppCompatActivity() { // 用MutableLiveData存储标签数据 private val fetchedTags = MutableLiveData<List<Tags>>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) fetchTags() // 观察LiveData的变化 fetchedTags.observe(this) { tags -> tags?.let { println(it[0].name) fetchBooks() makeMapOutOfTagsAndBooks() } } } fun fetchTags() { // 异步请求接口,成功后更新LiveData OkHttpClient().newCall(Request.Builder().url("your-api-url").build()).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { // 处理失败 } override fun onResponse(call: Call, response: Response) { response.body?.let { val tags = Gson().fromJson(it.string(), object : TypeToken<List<Tags>>() {}.type) runOnUiThread { fetchedTags.value = tags } } } }) } }
关键注意点
- 永远不要在主线程执行网络请求,Android会抛出
NetworkOnMainThreadException,所以异步请求必须在后台线程执行,完成后切回主线程处理结果 - 处理
fetchedTags为null的情况,避免空指针异常(比如用?.let或者空合并运算符)
内容的提问来源于stack exchange,提问作者Zim
相关产品推荐
相关产品推荐

