Android应用点击下载图片按钮崩溃,报java.lang.NullPointerException
解决点击下载按钮触发的NullPointerException问题
点击下载按钮时应用崩溃,抛出java.lang.NullPointerException异常,异常堆栈指向com.$$$$$$.fieldforce.adapter.InstallDocAdapter的saveToGallery方法。
Logcat异常信息
Exception java.lang.NullPointerException: at android.graphics.Bitmap.compress (Bitmap.java:1434) at com.$$$$$$.fieldforce.adapter.InstallDocAdapter.saveToGallery (InstallDocAdapter.java:123) at com.$$$$$$.fieldforce.adapter.InstallDocAdapter.access$100 (InstallDocAdapter.java:40) at com.$$$$$$.fieldforce.adapter.InstallDocAdapter$1.onClick (InstallDocAdapter.java:75) at android.view.View.performClick (View.java:7488) at android.view.View.performClickInternal (View.java:7464) at android.view.View.access$3700 (View.java:841) at android.view.View$PerformClick.run (View.java:28911) at android.os.Handler.handleCallback (Handler.java:938) at android.os.Handler.dispatchMessage (Handler.java:99) at android.os.Looper.loopOnce (Looper.java:233) at android.os.Looper.loop (Looper.java:344) at android.app.ActivityThread.main (ActivityThread.java:8212) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:584) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1034)
问题代码分析
对应的saveToGallery方法存在两处关键空指针风险:
- Bitmap对象可能为null:
BitmapFactory.decodeByteArray在解码无效字节数组(比如Base64字符串不合法、损坏)时会返回null,直接调用bitmap.compress会触发NPE,这正是本次崩溃的原因。 - FileOutputStream可能为null:创建输出流时如果抛出异常(如无存储权限、目录创建失败),仅打印堆栈不做后续处理,后续调用
flush()、close()也会触发空指针。
原代码:
private void saveToGallery(String attachment){ byte [] encodeByte = Base64.decode(attachment,Base64.DEFAULT); Bitmap bitmap = BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length); FileOutputStream outputStream = null; File file = Environment.getExternalStorageDirectory(); File dir = new File(file.getAbsolutePath() + "/$$$$$$ Downloads"); dir.mkdirs(); String filename = String.format("%d.png",System.currentTimeMillis()); File outFile = new File(dir,filename); try{ outputStream = new FileOutputStream(outFile); }catch (Exception e){ e.printStackTrace(); } bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream); try{ outputStream.flush(); }catch (Exception e){ e.printStackTrace(); } try{ outputStream.close(); Toast.makeText(context,"Downloaded image ....",Toast.LENGTH_LONG).show(); } catch (Exception e){ e.printStackTrace(); } }
修复方案
1. 增加Bitmap空判断
在调用compress前检查Bitmap是否为null,若为空则提示用户图片数据异常,终止后续操作。
2. 处理FileOutputStream空指针
创建输出流后判断是否为null,避免后续IO操作触发空指针。
3. 补充存储权限检查
Android 6.0及以上版本需要动态申请WRITE_EXTERNAL_STORAGE(针对旧版本存储API)或使用MediaStore/Scoped Storage,确保应用有写入外部存储的权限。
4. 增加输入参数校验
先判断attachment是否为空或空字符串,避免Base64解码出错。
修复后的代码示例
private void saveToGallery(String attachment){ // 校验输入参数 if (TextUtils.isEmpty(attachment)) { Toast.makeText(context, "图片数据为空", Toast.LENGTH_LONG).show(); return; } byte[] encodeByte = Base64.decode(attachment, Base64.DEFAULT); Bitmap bitmap = BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length); // 校验Bitmap是否有效 if (bitmap == null) { Toast.makeText(context, "图片数据解析失败", Toast.LENGTH_LONG).show(); return; } FileOutputStream outputStream = null; File file = Environment.getExternalStorageDirectory(); File dir = new File(file.getAbsolutePath() + "/$$$$$$ Downloads"); // 确保目录创建成功 if (!dir.exists() && !dir.mkdirs()) { Toast.makeText(context, "目录创建失败", Toast.LENGTH_LONG).show(); bitmap.recycle(); // 回收Bitmap避免内存泄漏 return; } String filename = String.format("%d.png", System.currentTimeMillis()); File outFile = new File(dir, filename); try{ outputStream = new FileOutputStream(outFile); }catch (Exception e){ e.printStackTrace(); Toast.makeText(context, "创建文件失败", Toast.LENGTH_LONG).show(); bitmap.recycle(); return; } // 校验输出流是否有效 if (outputStream == null) { Toast.makeText(context, "文件输出流创建失败", Toast.LENGTH_LONG).show(); bitmap.recycle(); return; } try{ bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); outputStream.flush(); outputStream.close(); Toast.makeText(context, "图片已下载", Toast.LENGTH_LONG).show(); } catch (Exception e){ e.printStackTrace(); Toast.makeText(context, "保存图片失败", Toast.LENGTH_LONG).show(); } finally { // 回收Bitmap释放内存 if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); } // 确保流关闭 try { if (outputStream != null) { outputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者Rookie
相关产品推荐
相关产品推荐

