Kotlin中RecyclerView适配器调用setImageResource报空指针异常
问题现象
调用setImageResource方法时触发致命空指针异常,异常日志如下:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageResource(int)' on a null object reference
异常出现在Kotlin开发的桌游管理应用的自定义RecyclerView适配器BgAdapter中,触发位置为onBindViewHolder生命周期内,根据桌游收藏状态切换收藏图标资源的代码段:
if (currentBg.faved) { holder.bgFavIcon.setImageResource(R.drawable.ic_check) } else { holder.bgFavIcon.setImageResource(R.drawable.ic_add_light) }
根因分析
findViewById在匹配不到对应id的控件时会返回null,你的代码中bgFavIcon被声明为非空ImageView类型,但实际运行时获取到的是null值,调用setImageResource就会触发空指针。
导致findViewById返回null的常见原因:
- 传入Adapter的
layoutId对应的Recycler item布局文件中,不存在id为add_light_icon的ImageView控件 - 控件id拼写错误,和布局文件中定义的id不一致
- 导入了错误的R类,导致代码中引用的
R.id.add_light_icon不是当前模块下的对应控件id - 存在多item视图类型时,部分类型的item布局未添加该id的控件,滑动到对应item时触发异常
排查步骤
- 打开构造Adapter时传入的
layoutId对应的XML布局文件,全局搜索add_light_icon,确认该id对应的控件是ImageView类型,且直接属于当前item布局,而非其他布局(Activity布局、弹窗布局、其他列表item布局) - 核对id拼写,确保代码中引用的id和布局中定义的id完全一致,无大小写错误、字符遗漏
- 检查文件头部的R类导入语句,确保导入的是当前项目模块的R类,而非其他依赖库/模块的R类
- 如果Adapter实现了多viewType逻辑,逐一检查所有类型的item布局,确认都包含对应id的ImageView控件
修复方案
- 修正布局匹配问题
在对应的Recycler item布局文件中添加对应id的ImageView控件,示例:
<ImageView android:id="@+id/add_light_icon" android:layout_width="24dp" android:layout_height="24dp" android:contentDescription="收藏按钮" android:src="@drawable/ic_add_light"/>
- 增强代码健壮性
参考你对bgName、bgEditor的处理方式,将ViewHolder中通过findViewById初始化的控件都声明为可空类型,使用安全调用符?.执行操作,避免id匹配失败时直接崩溃。
修改后的ViewHolder代码:
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val bgImage: ImageView? = view.findViewById(R.id.image_item) val bgName: TextView? = view.findViewById(R.id.name_item) val bgEditor: TextView? = view.findViewById(R.id.editor_item) val bgFavIcon: ImageView? = view.findViewById(R.id.add_light_icon) }
对应修改onBindViewHolder中的控件调用逻辑:
// Glide加载图片逻辑 holder.bgImage?.let { Glide.with(context).load(Uri.parse(currentBg.image_url)).into(it) } // 收藏状态图标设置逻辑 if (currentBg.faved) { holder.bgFavIcon?.setImageResource(R.drawable.ic_check) } else { holder.bgFavIcon?.setImageResource(R.drawable.ic_add_light) } // 收藏按钮点击事件 holder.bgFavIcon?.setOnClickListener { currentBg.faved = !currentBg.faved val repo = BgRepository() repo.updateBg(currentBg) }
- 优化建议
*不要在onBindViewHolder中重复创建BgRepository实例,会产生大量无意义的内存开销,可以将Repository实例通过Adapter构造函数传入,全局复用。
内容的提问来源于stack exchange,提问作者Accolade
相关产品推荐
相关产品推荐

