由 java.lang.NullPointerException 引起:尝试在空对象引用上调用虚拟方法“int android.graphics.Bitmap.getWidth()”

Posted

技术标签:

【中文标题】由 java.lang.NullPointerException 引起:尝试在空对象引用上调用虚拟方法“int android.graphics.Bitmap.getWidth()”【英文标题】:Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference 【发布时间】:2017-03-19 21:38:45 【问题描述】:

我有 BitmapScalingHelper.java:

public class BitmapScalingHelper

    public static Bitmap decodeResource(Resources res, int resId, int dstWidth, int dstHeight)
    
        Options options = new Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
        options.inJustDecodeBounds = false;

        options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,
                dstHeight);

        Bitmap unscaledBitmap = BitmapFactory.decodeResource(res, resId, options);

        return unscaledBitmap;
    

    public static Bitmap decodeFile(String filePath, int dstWidth, int dstHeight)
    
        Options options = new Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, options);

        options.inJustDecodeBounds = false;
        options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,
                dstHeight);

        Bitmap unscaledBitmap = BitmapFactory.decodeFile(filePath, options);

        return unscaledBitmap;
    


    public static int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, int dstHeight)
    
        final float srcAspect = (float)srcWidth / (float)srcHeight;
        final float dstAspect = (float)dstWidth / (float)dstHeight;

        if (srcAspect > dstAspect)
        
            return srcWidth / dstWidth;
        
        else
        
            return srcHeight / dstHeight;
        
    

    public static Bitmap createScaledBitmap(Bitmap unscaledBitmap, int dstWidth, int dstHeight)
    
        Rect srcRect = calculateSrcRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight());

        Rect dstRect = calculateDstRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),
                dstWidth, dstHeight);

        Bitmap scaledBitmap = Bitmap.createBitmap(dstRect.width(), dstRect.height(),
                Config.ARGB_8888);

        Canvas canvas = new Canvas(scaledBitmap);
        canvas.drawBitmap(unscaledBitmap, srcRect, dstRect, new Paint(Paint.FILTER_BITMAP_FLAG));

        return scaledBitmap;
    

    public static Rect calculateSrcRect(int srcWidth, int srcHeight)
    
        System.out.print("Scr" + srcWidth + " " + srcHeight);
        return new Rect(0, 0, srcWidth, srcHeight);
    

    public static Rect calculateDstRect(int srcWidth, int srcHeight, int dstWidth, int dstHeight)
    
        final float srcAspect = (float)srcWidth / (float)srcHeight;
        final float dstAspect = (float)dstWidth / (float)dstHeight;

        if (srcAspect > dstAspect)
        
            return new Rect(0, 0, dstWidth, (int)(dstWidth / srcAspect));
        
        else
        
            return new Rect(0, 0, (int)(dstHeight * srcAspect), dstHeight);
        
    

在这个类中有:

createScaledBitmap()

...返回一个缩放的位图图像。

在另一个班级,我有这个方法:

public Bitmap readSelectedBitmapFromFile(Context context, String fileName)
    
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(metrics);

        Bitmap scaledBitmap = getDefaultBitmap(context);

        try 
            File themeParentDir = context.getDir(THEME_DIRECTORY_NAME, Context.MODE_PRIVATE); //Creating an internal dir;
            File themeSubDir = new File(themeParentDir, THEME_SUB_DIRECTORY_NAME + getThemeBasedDirectoryNumber(m_SelectedTheme));
            themeSubDir.mkdir();

            File themeFileWithinDir = new File(themeSubDir, fileName); //Getting a file within the dir.

            if(themeFileWithinDir.exists())
            
                // Part 1: Decode image
                Bitmap unscaledBitmap = BitmapScalingHelper.decodeFile(themeFileWithinDir.getPath(), metrics.widthPixels, metrics.heightPixels);

                // Part 2: Scale image
                scaledBitmap = BitmapScalingHelper.createScaledBitmap(unscaledBitmap, metrics.widthPixels, metrics.heightPixels);
                unscaledBitmap.recycle();
            

            m_SelectedBitmap = scaledBitmap;

        
        catch (Error e) 
            e.printStackTrace();
        

        return scaledBitmap;
    

此代码在许多设备上都运行良好。但它在某些设备上崩溃了。谁能帮帮我?

我收到这样的日志:

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3254)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350)
       at android.app.ActivityThread.access$1100(ActivityThread.java:222)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:158)
       at android.app.ActivityThread.main(ActivityThread.java:7229)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
       at in.plackal.lovecyclesfree.util.BitmapScalingHelper.createScaledBitmap(SourceFile:62)
       at in.plackal.lovecyclesfree.general.ThemeManager.readSelectedBitmapFromFile(SourceFile:202)
       at in.plackal.lovecyclesfree.activity.SplashActivity.onCreate(SourceFile:70)
       at android.app.Activity.performCreate(Activity.java:6876)
       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135)
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350)
       at android.app.ActivityThread.access$1100(ActivityThread.java:222)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:158)
       at android.app.ActivityThread.main(ActivityThread.java:7229)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

如果是权限问题,它不应该在低于 Android-M 版本的情况下崩溃,但在某些 Android-M 之前的设备中也会崩溃。

【问题讨论】:

哪一行导致异常(来自方法而不是整个类。) @PavanBilagi 您是否找到了更好的内存管理解决方案,我发现在 xperia xa 中几乎每次都会发生这种情况。但是,如果您处于调试模式并在按 f9 之前在解码文件上稍等片刻,则它可以工作。并且在几乎所有其他设备上都可以正常工作。我正在像你一样使用一些东西。 【参考方案1】:

您面临的问题是您试图在createScaledBitmap 函数中的unscaledBitmap 上使用getWidth()。显然,您的unscaledBitmap 有时是null;并且调用getWidth() 会导致空指针异常。

根本原因是 decodeResource 出于某种原因返回 null。

原因可能包括 -

    没有读取权限 图像文件已损坏 内存不足,无法解码文件 资源不存在 options 变量中指定的选项无效。

我建议你修改你的代码,在解码的位图上包含一个空检查,记录它并从那里在你看到错误发生的特定设备上进行调试。

也可能是在第二次调用 decodeResource 时,您正在重复使用的 options 变量的解释不同。您可以尝试在那里传递一个空值。

修改后的代码应该如下-

public class BitmapScalingHelper

    public static Bitmap decodeResource(Resources res, int resId, int dstWidth, int dstHeight)
    
        Options options = new Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
        options.inJustDecodeBounds = false;

        options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,
                dstHeight);

        options = new Options(); 
        //May use null here as well. The funciton may interpret the pre-used options variable in ways hard to tell.
        Bitmap unscaledBitmap = BitmapFactory.decodeResource(res, resId, options);

        if(unscaledBitmap == null)
        
            Log.e("ERR","Failed to decode resource - " + resId + " " + res.toString());
            return null;
        

        return unscaledBitmap;
    

【讨论】:

【参考方案2】:

对于 Android 10 ,将此行添加到清单中:

android:requestLegacyExternalStorage="true"

请注意,您也必须添加所需的权限:

READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE

【讨论】:

如果我把这行放在其他 android 版本中会发生什么?【参考方案3】:

简单的答案: 请按照以下步骤操作..

    长按已安装的APP图标。 转到应用信息部分。 现在点击应用权限部分 启用存储权限

现在可以正常使用了

enter image description here

enter image description here

【讨论】:

【参考方案4】:

好吧,我反复遇到这个错误,我对这个问题的解决方法是确保您使用 .png 图像作为位图图像并将其保存在可绘制文件夹中。以前我将它用作矢量资产。 这对我来说很好。

【讨论】:

【参考方案5】:

您正在使用:Bitmap decodeFile (String pathName) 如果文件解码失败,此方法可能会返回 null。 我认为这可能与某些设备上的权限问题或不支持的图像格式有关。 如果您使用的是 GIF,请尝试 https://developer.android.com/reference/android/graphics/Movie.html

【讨论】:

但它也在 kitkat (4.4.4) 中崩溃了 能否提供您的清单权限以及您如何将文件编码为 THEME_DIRECTORY_NAME ?【参考方案6】:

有一些原因可能会导致错误。

    AndroidManifest.xml 中缺少权限。读取或写入权限。 文件不存在,或者您尝试访问的文件无法解码为位图。

从您发布的代码中,我找不到任何逻辑错误。以下是我的建议:

    更换另一张图片并测试。

    尝试使用 Glide 或 Fresco 等 ImageLoader 库并进行测试。

【讨论】:

【参考方案7】:

如果您使用创建不当的库 jar,并且在您的 gradle 上将 minifyEnabled 设置为 true,也可能会导致此错误。

【讨论】:

以上是关于由 java.lang.NullPointerException 引起:尝试在空对象引用上调用虚拟方法“int android.graphics.Bitmap.getWidth()”的主要内容,如果未能解决你的问题,请参考以下文章

Maven + Spring + Hibernate:hibernate3-maven-plugin hbm2ddl 失败,原因是“Caused by: java.lang.NullPointerEx

无法在 null 对象上调用方法 replace(),但存在字符串

jQuery 插件可由控制台触发,但不能由函数触发 - 为啥会这样?

常用宏定义 - 由角度转换弧度由弧度转换角度

由 coercion 引入的 NAs 由 knn 中的 coercionError 引入

如何区分两个“onpause”事件 - 由单击“暂停”按钮引起,以及由到达媒体片段末尾引起?