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

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方法存在两处关键空指针风险:

  1. Bitmap对象可能为null:BitmapFactory.decodeByteArray在解码无效字节数组(比如Base64字符串不合法、损坏)时会返回null,直接调用bitmap.compress会触发NPE,这正是本次崩溃的原因。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 11:45:33