You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 10:48:03