Android - Bitmap.CreateBitmap - 空指针异常

时间:2015-09-15 07:39:47

标签: c# android bitmap xamarin xamarin.android

有时当我尝试创建模糊的位图时,我会收到“空指针异常”。

发生在这段代码中(我最近开始捕获异常,所以至少它不会使应用程序崩溃):

try
{
    using (Bitmap.Config config = Bitmap.Config.Rgb565) {
        return Bitmap.CreateBitmap (blurredBitmap, width, height, config);
    }
}
catch (Java.Lang.Exception exception)
{
    Util.Log(exception.ToString());
}

有关我传入“CreateBitmap”方法的参数的详细信息,请参阅这些图片:

enter image description here

以下是扩展参数:

enter image description here

完全例外:

  

exception {Java.Lang.NullPointerException:类型异常   抛出'Java.Lang.NullPointerException'。在   System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()   [0x0000b] in   /Users/builder/data/lanes/2058/58099c53/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61   在Android.Runtime.JNIEnv.CallStaticObjectMethod(IntPtr jclass,   IntPtr jmethod,Android.Runtime.JValue * parms)[0x00064] in   /Users/builder/data/lanes/2058/58099c53/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.g.cs:1301   在Android.Graphics.Bitmap.CreateBitmap(System.Int32 []颜色,Int32   width,Int32 height,Android.Graphics.Config config)[0x00088] in   /Users/builder/data/lanes/2058/58099c53/source/monodroid/src/Mono.Android/platforms/android-22/src/generated/Android.Graphics.Bitmap.cs:735   在Psonar.Apps.Droid.PayPerPlay.StackBlur.GetBlurredBitmap   (Android.Graphics.Bitmap原创,Int32半径)[0x00375] in   d:\开发\ psonar \源\ Psonar.Apps \ Psonar.Apps.Droid \ Psonar.Apps.Droid.PayPerPlay \公用事业\ StackBlur.cs:123   ---托管异常堆栈跟踪结束--- java.lang.NullPointerException at   android.graphics.Bitmap.createBitmap(Bitmap.java:687)at   android.graphics.Bitmap.createBitmap(Bitmap.java:707)at   dalvik.system.NativeStart.run(本机方法)   } Java.Lang.NullPointerException

不确定这可能是Xamarin中的错误还是传递的参数错误。

1 个答案:

答案 0 :(得分:2)

我收到了Xamarin团队成员之一的回复 - Jonathan Pryor:

  

NullPointerException来自Java代码:

     
    

在android.graphics.Bitmap.createBitmap(Bitmap.java:687)     在android.graphics.Bitmap.createBitmap(Bitmap.java:707)     在dalvik.system.NativeStart.run(原生方法)

  
     

快速浏览各种版本,Jelly Bean可能适合:

     

https://github.com/android/platform_frameworks_base/blob/jb-release/graphics/java/android/graphics/Bitmap.java#L687

     
    return nativeCreate(colors, offset, stride, width, height,
                        config.nativeInt, false);
  
     

快速浏览周围的方法体,可以看出config   未检查null-ness,因此如果传递null,则会产生此结果   在NullPointerException中。

     

但问题是你没有传递null:

using (Bitmap.Config config = Bitmap.Config.Rgb565) {
    return Bitmap.CreateBitmap (blurredBitmap, width, height, config);
}
     

......或者是你?

     

我建议您删除 using块:

return Bitmap.CreateBitmap (blurredBitmap, width, height,
        Bitmap.Config.Rgb565);
     

这是我认为可能会发生的事情,但首先是一个题外话:

     

Xamarin.Android的核心深处有一个Java之间的映射   对象及其相应的C#包装器对象。构造函数   调用,Java.Lang.Object.GetObject()等将创建   映射; Java.lang.Object.Dispose()将删除映射。

     

这是对象身份的核心部分:当Java实例是   暴露于C#代码并创建了一个C#包装器,相同的 C#包装器   应该继续为该Java实例重用实例。

     

这样做的隐含结果是任何实例都是有效的    global ,因为如果有多个代码路径/ threads / etc.获取同一Java实例的JNI句柄,它们将获得相同的C#包装器。

     

这让我们回到了我的假设和你的代码块:   Bitmap.Config是一个Java枚举,意味着每个成员都是一个Java对象。   此外,它们是全局值,因此每个线程都可以访问   那些成员,意思是C#Bitmap.Config.Rgb565实例   实际上是一个全局变量。

     

你是Dispose()的全局变量。

     

哪个“很好”,因为 next 时间Bitmap.Config.Rgb565是   访问时,将创建一个新的包装器。

     

但问题是,如果您有多个线程访问   Bitmap.Config.Rgb565在同一时间,每个都在尝试   Dispose()一个实例。在这一点上,它完全合情合理   两个线程可以引用相同的包装器实例,并且   因此,来自一个线程的Dispose()将对所使用的实例进行无效   另一个线程。

     

哪会导致null传递给Bitmap.createBitmap()   打电话,这正是你所观察到的。

     

请尝试删除using块,看看这是否有用。

The whole thread is accessible here.

然后我问:

  

Jonathan Pryor - 为这个建议欢呼。我的问题是,如果我   删除using语句,会引入内存泄漏吗?含义   如果我停止处理新的配置实例?

他回答说:

  

这就是GC的用途!

     

(在这里插入咳嗽和笑声。)

     

我们可以狡辩一点。我认为它不是内存泄漏,   因为记忆力很好,众所周知;不断访问   Bitmap.Config.Rgb565将返回先前创建的实例,   不经常创建新实例。这样没有“泄漏”。

     

我会反而认为实例和底层的GREF是一个   “税”;它被“烧毁”,这是经营成本的一部分。虽然它   为了最大限度地降低这些成本会“很好”,删除是不切实际的   所有这些(例如我们通过.class_ref“失去”每个班级的GREF,   用于查找方法ID ...),至少不与当前相关   架构。

     

(我也想不出会导致的替代架构   不同的成本/“税收”。虽然我对允许有一些想法   在某些方面需要改进的地方,它们并不大。)

     

我建议不要担心Bitmap.Config.Rgb565和类似的问题   成员太多,除非/直到剖析器或GREF计数显示   否则。