Android使用Glide加载图片报NullPointerException如何解决?
问题日志
2022-06-20 13:19:27.605 20830-20830/com.example.moveapplication E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.moveapplication, PID: 20830 java.lang.NullPointerException: Argument must not be null at com.bumptech.glide.util.Preconditions.checkNotNull(Preconditions.java:29) at com.bumptech.glide.util.Preconditions.checkNotNull(Preconditions.java:23) at com.bumptech.glide.RequestBuilder.into(RequestBuilder.java:768) at com.example.moveapplication.activities.MainActivity.openBottomSheetDialog$lambda-2(MainActivity.kt:100) at com.example.moveapplication.activities.MainActivity.$r8$lambda$acEx44X-0qqDdGYpms4KzfGag5A(Unknown Source:0) at com.example.moveapplication.activities.MainActivity$$ExternalSyntheticLambda3.onSuccess(Unknown Source:15) at com.google.android.gms.tasks.zzm.run(com.google.android.gms:play-services-tasks@@18.0.1:1) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
根因定位
报错触发点为Glide加载代码的.into(uImage)行,核心原因有2个:
- 控件获取逻辑错误:
sheetIvProfileImage等控件属于BottomSheet弹窗的独立布局R.layout.bottom_sheet_dialog,不属于MainActivity自身的布局文件,直接调用Activity的findViewById无法找到对应控件,返回null。Glide的into()方法强制要求传入的ImageView参数非空,直接触发空指针异常。 - 代码执行顺序错乱:原代码先发起Firebase异步数据请求,再初始化弹窗、加载弹窗布局,异步请求回调时机不固定,大概率在弹窗布局未完成加载时就执行控件赋值、图片加载逻辑,进一步加剧空指针风险。另外原代码遗漏了
bottomSheetDialog.show()调用,即使修复空指针问题,弹窗也无法正常展示。
修复方案
- 调整代码执行顺序:先完成BottomSheetDialog初始化、弹窗布局inflate操作,再发起Firebase数据请求
- 所有弹窗内的控件,统一从inflate得到的
bottomSheetView对象上调用findViewById获取,禁止使用Activity的findViewById查找弹窗布局内的控件 - 数据回调中增加多层空判断:同时判断
document存在、ownerModel非空、图片地址非空、控件实例非空后,再执行Glide加载和文本赋值逻辑 - 初始化完成后调用
show()方法展示弹窗
修复后完整代码如下:
private fun openBottomSheetDialog(position: Int) { val publisher = posts[position].publisher // 先初始化弹窗、加载弹窗布局 val bottomSheetDialog = BottomSheetDialog(this, R.style.BottomSheetDialogTheme) val bottomSheetView = LayoutInflater.from(this).inflate( R.layout.bottom_sheet_dialog, findViewById(R.id.bottomSheet) ) // 从弹窗布局对象上获取控件,不要用Activity的findViewById val uImage = bottomSheetView.findViewById<ImageView>(R.id.sheetIvProfileImage) val uNumber = bottomSheetView.findViewById<TextView>(R.id.sheetTvOwnerNumber) val uEmail = bottomSheetView.findViewById<TextView>(R.id.tvOwnerEmail) val uAbout = bottomSheetView.findViewById<TextView>(R.id.tvOwnerAbout) val uTitle = bottomSheetView.findViewById<TextView>(R.id.sheetTvOwnerTitle) // 布局和控件初始化完成后再请求数据 val ownersRef = FirebaseFirestore.getInstance().collection("owners").document(publisher) ownersRef.get().addOnSuccessListener { document -> val ownerModel = document.toObject(Owner::class.java) // 非空判断后再操作 ownerModel?.let { model -> uTitle.text = model.username uNumber.text = model.phoneNumber uEmail.text = model.email uAbout.text = model.about // 图片地址非空再加载 if (!model.profileImage.isNullOrEmpty()) { Glide.with(this) .load(model.profileImage) .into(uImage) } } } // 绑定布局、展示弹窗 bottomSheetDialog.apply { setContentView(bottomSheetView) setCancelable(true) show() } }
额外优化点:如果Firebase请求耗时较长,用户提前关闭弹窗会导致Activity销毁,Glide加载可能出现内存泄漏,可在
addOnSuccessListener中增加判断Activity是否处于销毁状态的逻辑,规避生命周期关联问题。
内容的提问来源于stack exchange,提问作者Sam Kabiru
相关产品推荐
相关产品推荐

