如何解决RecyclerView加载空/Null列表时Android应用崩溃的问题
崩溃根因
- 错误日志已经明确指出崩溃发生在
ManageAdsFragment.kt第58行的强制类型转换环节:Retrofit请求返回的response.body()可能为null(比如接口无数据返回、响应异常场景下),你直接使用as List<adsModel>将可空类型强转为非空类型,触发了空指针异常。 - 你的
adsAdapter构造要求传入非空的List<adsModel>,传入null自然不符合参数要求导致崩溃。
解决方案
1. 先修复Fragment中getData方法的空值处理
对response.body()做空值兜底,null场景下默认返回空列表,同时过滤掉列表内可能存在的null元素,避免强转错误:
private fun getData() { val uid = auth.uid.toString() val call: Call<List<adsModel?>?>? = apiController .instance?.api?.getAds(uid) call?.enqueue(object : Callback<List<adsModel?>?>{ override fun onResponse( call: Call<List<adsModel?>?>, response: Response<List<adsModel?>?> ) { // null兜底为空列表,同时过滤列表内的null元素 val safeList = response.body()?.filterNotNull() ?: emptyList() val adapter = adsAdapter(safeList, this@ManageAdsFragment) binding.recyclerview.adapter = adapter } override fun onFailure(call: Call<List<adsModel?>?>, t: Throwable) { Toast.makeText(requireContext(), t.message.toString(), Toast.LENGTH_SHORT).show() } }) }
提示:
LinearLayoutManager初始化和setHasFixedSize配置不需要每次请求数据都重复执行,放到Fragment的onViewCreated生命周期里做一次初始化即可,减少不必要的重复操作。
2. 优化Adapter做更稳定的空兼容(可选,推荐)
给Adapter的列表参数加默认空列表,同时新增列表更新方法,后续刷新数据不需要重复创建Adapter实例,性能更优:
// 构造参数默认赋值为空列表,确保列表永远非空 class adsAdapter( private val adsList: List<adsModel> = emptyList(), // 建议用你定义的OnItemClickListener接口做参数,不要直接传Fragment,降低耦合 private val listener: OnItemClickListener ): RecyclerView.Adapter<adsAdapter.adsViewHolder>(){ // 新增列表更新方法,后续刷新数据直接调用即可 fun updateList(newList: List<adsModel>) { adsList = newList notifyDataSetChanged() // 对刷新动画有要求可以替换为DiffUtil实现局部刷新 } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): adsViewHolder { val itemView = LayoutInflater.from(parent.context).inflate(R.layout.ads_item, parent, false) return adsViewHolder(itemView) } override fun onBindViewHolder(holder: adsViewHolder, position: Int) { val currentItem = adsList[position] holder.title.text = currentItem.title val adData = "${currentItem.watched}/${currentItem.quantity}" holder.adsData.text = adData when(currentItem.status.toString()){ "1" -> { holder.onlineImageView.visibility = View.VISIBLE holder.completeImageView.visibility = View.INVISIBLE holder.cancelImageView.visibility = View.INVISIBLE } "2" -> { holder.onlineImageView.visibility = View.INVISIBLE holder.completeImageView.visibility = View.VISIBLE holder.cancelImageView.visibility = View.INVISIBLE } "3" -> { holder.onlineImageView.visibility = View.INVISIBLE holder.completeImageView.visibility = View.INVISIBLE holder.cancelImageView.visibility = View.VISIBLE } } } override fun getItemCount() = adsList.size inner class adsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener{ val onlineImageView: ImageView = itemView.findViewById(R.id.onlineImageView) val completeImageView: ImageView = itemView.findViewById(R.id.completeImageView) val cancelImageView: ImageView = itemView.findViewById(R.id.cancelImageView) val adsData: TextView = itemView.findViewById(R.id.adsDataTextView) val title: TextView = itemView.findViewById(R.id.titleTextView) init { itemView.setOnClickListener(this) } override fun onClick(v: View?) { val position = adapterPosition if (position != RecyclerView.NO_POSITION) { listener.onItemClick(position) } } } interface OnItemClickListener{ fun onItemClick(position: Int) } }
提示:让你的
ManageAdsFragment实现adsAdapter.OnItemClickListener接口即可,不需要把整个Fragment作为参数传入Adapter,代码耦合度会更低。
内容的提问来源于stack exchange,提问作者Steve Harrington
相关产品推荐
相关产品推荐

