Kotlin开发TabbedActivity时RecyclerView报No adapter attached错误
错误原因
- 核心问题:RecyclerView的
layoutManager和adapter是在Retrofit的异步网络请求回调里才设置的,界面首次渲染阶段RecyclerView没有绑定任何适配器,所以触发了No adapter attached; skipping layout警告 - 额外问题1:类名命名为
thirdtabFragment但实际继承了AppCompatActivity,如果是Tab页对应的组件应该继承Fragment,逻辑也需要对应调整(如果实际是独立Activity可忽略该点) - 额外问题2:使用
response.body()!!非空断言风险极高,网络请求返回的body可能为空,会直接触发崩溃
修复方案
首先改造ScoreAdapter支持动态更新数据:
class ScoreAdapter(private var contenderList: List<Item> = emptyList()) : RecyclerView.Adapter<ScoreAdapter.ViewHolder>() { // 新增数据更新方法 fun updateData(newList: List<Item>) { contenderList = newList notifyDataSetChanged() // 后续可替换为DiffUtil提升列表刷新性能 } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.score_row, parent, false) return ViewHolder(view) } override fun getItemCount() = contenderList.size override fun onBindViewHolder(holder: ViewHolder, position: Int) { val contender = contenderList[position] holder.contenderName.text = contender.contenderName } class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ val contenderName: TextView = itemView.findViewById(R.id.contenderName_tv) } }
如果当前类是独立Activity,改造thirdtabFragment逻辑:
class thirdtabFragment : AppCompatActivity() { private lateinit var binding: ThirdtabBinding // 提前初始化适配器 private val scoreAdapter = ScoreAdapter() override fun onCreate(savedInstanceState: Bundle?){ super.onCreate(savedInstanceState) binding = ThirdtabBinding.inflate(layoutInflater) val view = binding.root setContentView(view) // 页面初始化阶段就完成RecyclerView配置 binding.recyclerView.apply { layoutManager = LinearLayoutManager(this@thirdtabFragment) adapter = scoreAdapter } val apiInterface = APIClient.client.create(ApiInterface::class.java) val call = apiInterface.getScore() call.enqueue(object : Callback<List<Item>> { override fun onResponse(call: Call<List<Item>>, response: Response<List<Item>>) { Log.d("Success!", response.toString()) // 替换非空断言做空安全处理 response.body()?.let { list -> showContenders(list) } ?: run { Log.e("Query Error", "返回数据为空") } } override fun onFailure(call: Call<List<Item>>, t: Throwable) { Log.e("Failed Query :(", t.toString()) } }) } private fun showContenders(contenderList: List<Item>) { // 直接更新适配器数据 scoreAdapter.updateData(contenderList) } }
如果当前类是Tab页对应的Fragment,调整为Fragment标准逻辑:
class thirdtabFragment : Fragment() { private var _binding: ThirdtabBinding? = null private val binding get() = _binding!! private val scoreAdapter = ScoreAdapter() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = ThirdtabBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 初始化RecyclerView binding.recyclerView.apply { layoutManager = LinearLayoutManager(requireContext()) adapter = scoreAdapter } // 发起网络请求 val apiInterface = APIClient.client.create(ApiInterface::class.java) val call = apiInterface.getScore() call.enqueue(object : Callback<List<Item>> { override fun onResponse(call: Call<List<Item>>, response: Response<List<Item>>) { Log.d("Success!", response.toString()) response.body()?.let { list -> showContenders(list) } ?: run { Log.e("Query Error", "返回数据为空") } } override fun onFailure(call: Call<List<Item>>, t: Throwable) { Log.e("Failed Query :(", t.toString()) } }) } private fun showContenders(contenderList: List<Item>) { scoreAdapter.updateData(contenderList) } override fun onDestroyView() { super.onDestroyView() // 清理绑定避免内存泄漏 _binding = null } }
内容的提问来源于stack exchange,提问作者expreiss
相关产品推荐
相关产品推荐

