使用OkHttp获取谷歌表格数据后,如何正确初始化RecyclerViewAdapter
解决OkHttp请求谷歌Sheets API后RecyclerView适配的两个问题
针对你遇到的两个问题,直接给你可行的代码修改方案和逻辑说明:
问题1:子线程操作UI触发异常
OkHttp的enqueue回调默认在子线程执行,Android不允许在子线程中操作UI组件(包括更新RecyclerView的Adapter)。解决方法是把UI操作切换到主线程,用Activity自带的runOnUiThread方法即可。
问题2:数据未初始化就初始化Adapter触发异常
不要等数据加载完成才初始化Adapter,而是先创建空的数据集和Adapter,后续数据加载完成后再更新数据集并通知Adapter刷新。
修改后的ActivityChoosing核心代码示例
class ActivityChoosing : AppCompatActivity() { private lateinit var recyclerView: RecyclerView private lateinit var adapter: CustomAdapter // 用可变列表存储数据,初始为空 private val dataModels = mutableListOf<YourDataModel>() // 替换成你的实际数据模型类 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_choosing) // 初始化RecyclerView和空Adapter recyclerView = findViewById(R.id.recycler_view) // 替换成你的RecyclerView ID recyclerView.layoutManager = LinearLayoutManager(this) adapter = CustomAdapter(dataModels) recyclerView.adapter = adapter // 启动API请求 fetchSheetsData() } private fun fetchSheetsData() { val okHttpClient = OkHttpClient() val request = Request.Builder() .url("你的谷歌Sheets API接口地址") .get() .build() okHttpClient.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { // 请求失败的处理,必须切换到主线程 runOnUiThread { Toast.makeText(this@ActivityChoosing, "加载失败: ${e.message}", Toast.LENGTH_SHORT).show() } } override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { response.body?.string()?.let { responseContent -> // 解析API返回的数据到dataModels列表,替换成你的实际解析逻辑 val parsedData = parseSheetsResponse(responseContent) // 切换到主线程更新数据和UI runOnUiThread { dataModels.clear() dataModels.addAll(parsedData) adapter.notifyDataSetChanged() // 通知Adapter数据已更新 } } } else { runOnUiThread { Toast.makeText(this@ActivityChoosing, "请求失败: ${response.code}", Toast.LENGTH_SHORT).show() } } } }) } // 示例解析方法,根据你的Sheets API返回格式实现 private fun parseSheetsResponse(response: String): List<YourDataModel> { // 这里用你习惯的解析方式(Gson/Moshi/手动解析)把JSON转成数据模型列表 // 比如:return Gson().fromJson(response, object : TypeToken<List<YourDataModel>>() {}.type) return emptyList() // 替换成实际解析结果 } }
逻辑说明
- 提前初始化空Adapter:在
onCreate中就创建好Adapter并绑定到RecyclerView,此时dataModels是空的可变列表,不会触发未初始化异常。Adapter持有这个列表的引用,后续数据更新时直接修改列表即可。 - 主线程更新UI:所有涉及UI的操作(更新Adapter、Toast提示)都放在
runOnUiThread的Lambda中,确保在主线程执行,避免跨线程操作UI的异常。 - 数据更新后通知Adapter:当API返回数据并解析完成后,清空原有列表、添加新数据,然后调用
adapter.notifyDataSetChanged()让RecyclerView刷新显示新数据。
如果想让列表更新更高效,可以用DiffUtil替代notifyDataSetChanged(),但对于基础场景,notifyDataSetChanged()已经足够解决问题。
内容的提问来源于stack exchange,提问作者Юля Муравьева
相关产品推荐
相关产品推荐

