Kotlin中OkHttp解析数据到RecyclerView时崩溃问题求助
问题排查与解决方案
核心原因
报错android.view.ViewRootImpl$CalledFromWrongThreadException明确说明:只有创建View层级的原始线程(主线程/UI线程)才能操作View。而OkHttp的enqueue异步回调(onResponse方法)是在后台子线程执行的,你直接在这个方法里修改noBankView的可见性、初始化RecyclerView的布局管理器和适配器,属于跨线程操作UI,直接触发了崩溃。
修复步骤
1. 将UI操作切换到主线程
把onResponse里的UI相关代码,用runOnUiThread包裹,或者用Handler.post(和你在onFailure里的写法一致),确保UI操作在主线程执行。
2. 提前初始化View变量
不要在网络回调里重复调用findViewById,建议在Activity的onCreate方法中提前初始化所有需要用到的View,避免重复查找,提升性能。
3. 优化空安全处理
避免用!!强制解包(比如saveBankResponseModel.data!!),改用空安全操作符?.配合let,防止空指针异常。
修改后的Activity关键代码
// 提前在Activity onCreate里初始化View private lateinit var noBankView: LinearLayout private lateinit var newRecyclerView: RecyclerView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.your_activity_layout) // 初始化View noBankView = findViewById(R.id.nobank_layout) newRecyclerView = findViewById(R.id.recyclerView) // 发起网络请求 callBankApi() } private fun callBankApi() { okHttpClient.newCall(request).enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { if(response.isSuccessful) { val saveBankResponseModel = json.decodeFromString<SaveBankResponseModel>( response.body!!.string() ) Log.d("Member Bank API","${saveBankResponseModel.data?.memberBank}") // 将UI操作切换到主线程 runOnUiThread { saveBankResponseModel.data?.memberBank?.let { bankList -> noBankView.visibility = View.GONE newRecyclerView.apply { layoutManager = LinearLayoutManager(this@MyWalletActivity) adapter = SavedBankAdapter(bankList) } } ?: run { // 处理data为null的情况,比如显示noBankView noBankView.visibility = View.VISIBLE } } } } override fun onFailure(call: Call, e: IOException) { runOnUiThread { Log.e("Bank API Error", e.message ?: "Unknown error") // 失败时可以显示错误提示 noBankView.visibility = View.VISIBLE } } }) }
其他优化建议
- 适配器命名规范:Kotlin类名建议用大驼峰命名,把
saved_bank_adapter改为SavedBankAdapter。 - 补全ViewHolder实现:你的适配器代码里缺少
BankViewHolder的完整实现,需要补全:
inner class BankViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val itemName: TextView = itemView.findViewById(R.id.bank_name) // 替换为你的布局ID val itemAccNum: TextView = itemView.findViewById(R.id.bank_acc_number) // 替换为你的布局ID }
- 避免全局变量滥用:不要把
saveBankResponseModel作为全局变量,直接在onResponse里局部声明即可,减少内存泄漏风险。
内容的提问来源于stack exchange,提问作者thw98
相关产品推荐
相关产品推荐

