生产环境NotificationAdapter空指针崩溃Firebase上报问题
生产环境NotificationAdapter空指针崩溃修复
问题现象
- 测试构建版本运行完全正常,生产构建版本触发崩溃
- 崩溃事件通过Firebase Crashlytics上报
- 崩溃核心信息:NotificationAdapter构造方法中声明为非空类型的
notificationDataArrayList参数,实际传入值为null
崩溃核心堆栈
Fatal Exception: java.lang.NullPointerException
Parameter specified as non-null is null: method kotlin.jvm.internal.j.e, parameter notificationDataArrayList
触发位置:com.ls.wo.sm.ui.notifications.NotificationAdapter.<init> (NotificationAdapter.kt:17)
问题代码片段
- NotificationAdapter原实现
class NotificationAdapter(notificationDataArrayList:ArrayList<NotificationsData>, private val clickListener:ClickListener, mcontext: Context): RecyclerView.Adapter<NotificationAdapter.NotificationViewHolder>() { val notificationArrayList : ArrayList<NotificationsData> val mcontext : Context inner class NotificationViewHolder (itemView: View): RecyclerView.ViewHolder(itemView){ val tv_notification_title : TextView val tv_notification_body : TextView val expensionBody: LinearLayout init { tv_notification_title = itemView.findViewById(R.id.til_request) tv_notification_body = itemView.findViewById(R.id.tv_notification_body) expensionBody = itemView.findViewById(R.id.layoutExpand) } } override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): NotificationViewHolder { val view : View = LayoutInflater.from(parent.context).inflate(R.layout.ui_notification_item,parent,false) return NotificationViewHolder(view) } override fun onBindViewHolder(holder:NotificationViewHolder,position: Int) { val recyclerData : NotificationsData = notificationArrayList[position] holder.tv_notification_title.text = recyclerData.Title holder.tv_notification_body.text = recyclerData.Body holder.itemView.setOnClickListener { clickListener.onItemClick(notificationArrayList[position]) } } override fun getItemCount(): Int { return notificationArrayList.size } init { notificationArrayList = notificationDataArrayList this.mcontext = mcontext } interface ClickListener{ fun onItemClick(dataModel: NotificationsData) } }
- Fragment中初始化Adapter的原代码
recyclerView = binding.notificationRv.apply { adapter = NotificationAdapter(response.body()!!.Data,this@NotificationsFragmentUI,context) layoutManager = manager adapter = adapter }
根因定位
- 初始化Adapter时使用了危险的非空断言
!!强取接口返回值:response.body()!!.Data。线上生产环境存在大量边缘场景:用户无通知数据、接口异常返回空结构、反序列化失败时Data字段会为null,此时!!会跳过判断直接把null值传给声明为非空的Adapter构造参数,触发Kotlin空安全校验崩溃。 - 测试环境无法复现的原因:Debug测试包默认关闭R8代码混淆压缩,且测试场景大多使用正常填充的测试数据,不会触发
Data为null的边缘情况;Release生产包开启代码优化,线上真实用户触发null场景时直接崩溃。 - 初始化代码中
adapter = adapter为冗余无效逻辑,无实际作用。
修复方案
- 移除危险的非空断言,对接口返回字段做空兜底,永远不要直接信任接口返回的数据
- Adapter增加空兼容逻辑,避免后续其他调用位置传入null触发崩溃
- 删除冗余无效代码
修复后代码
- Fragment中Adapter初始化逻辑
recyclerView = binding.notificationRv.apply { layoutManager = manager // 接口返回Data为null时兜底传空列表,杜绝传null给Adapter val notificationList = response.body()?.Data ?: arrayListOf() adapter = NotificationAdapter(notificationList, this@NotificationsFragmentUI, context) }
- Adapter空安全优化(建议配置,从组件层面避免空指针)
class NotificationAdapter( notificationDataArrayList: ArrayList<NotificationsData>?, private val clickListener: ClickListener, mcontext: Context ): RecyclerView.Adapter<NotificationAdapter.NotificationViewHolder>() { // 入参为null时内部兜底为空列表 private val notificationArrayList : ArrayList<NotificationsData> = notificationDataArrayList ?: arrayListOf() private val mcontext : Context = mcontext // 其余ViewHolder、onCreateViewHolder、onBindViewHolder逻辑保持原有实现不变 override fun getItemCount(): Int = notificationArrayList.size interface ClickListener{ fun onItemClick(dataModel: NotificationsData) } // 内部NotificationViewHolder类逻辑不变 }
内容的提问来源于stack exchange,提问作者Haseeb
相关产品推荐
相关产品推荐

