android.support.v7.graphics.Palette的宽度和高度必须大于0。

6

我有一些使用新的Palette类的代码,并且在Crashlytics上收到了这些崩溃报告,报告显示宽度和高度必须大于0。奇怪的是,这是我调用调色板代码的方式:

if( bitmap == null || bitmap.getHeight() <= 0 || bitmap.getWidth() <= 0){
   //do something
}else{
   Palette.Builder(bitmap).generate(new Palette.PaletteAsyncListener() {
.....
}

我不确定位图突然没有正确的高度或宽度是如何可能的。我不知道异常来自于我的哪一部分代码,因为报告仅包含调色板类内部的内容。

以下是异常信息:

java.lang.RuntimeException: An error occured while executing doInBackground()
       at android.os.AsyncTask$3.done(AsyncTask.java:300)
       at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
       at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
       at java.util.concurrent.FutureTask.run(FutureTask.java:242)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
       at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.IllegalArgumentException: width and height must be > 0
       at android.graphics.Bitmap.createBitmap(Bitmap.java:815)
       at android.graphics.Bitmap.createBitmap(Bitmap.java:794)
       at android.graphics.Bitmap.createBitmap(Bitmap.java:725)
       at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:601)
       at android.support.v7.graphics.Palette.scaleBitmapDown(Palette.java:282)
       at android.support.v7.graphics.Palette.access$100(Palette.java:67)
       at android.support.v7.graphics.Palette$Builder.generate(Palette.java:557)
       at android.support.v7.graphics.Palette$Builder$1.doInBackground(Palette.java:623)
       at android.support.v7.graphics.Palette$Builder$1.doInBackground(Palette.java:620)
       at android.os.AsyncTask$2.call(AsyncTask.java:288)
       at java.util.concurrent.FutureTask.run(FutureTask.java:237)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
       at java.lang.Thread.run(Thread.java:818)

我正在使用来自com.android.support:palette-v7:23+的Palette类。

有什么想法可能出了问题吗?


你确定位图有任何内容或者正在显示吗?调色板必须分析图像后,几毫秒之后你才能得到颜色。 - Mariano Zorrilla
我只在Crashlytics上收到错误报告,从未发生过在我的设备上。但是在调用调色板代码之前,我会检查是否为空和大小。 - casolorz
应用程序从未崩溃?您能否重新创建此问题?如果不能...也许一些用户使用低端智能手机,任务需要太长时间,并且调色板找不到空值(在调色板上崩溃而不是位图上)。 - Mariano Zorrilla
这个问题对我来说从未导致应用程序崩溃。我不确定为什么位图在调色板运行时会变为空,难道调色板没有对它的引用吗?也许位图正在被回收,但错误是否会与其被回收有关呢? - casolorz
我猜测错误是由监听器内部的代码引起的。你能否提供更多代码(在示例中省略的部分)? - Nulano
不是在监听器中出现的问题,这是完整的堆栈跟踪,并且永远不会返回到监听器。 - casolorz
3个回答

0

我认为你的代码没有任何问题。我正在查看你发布的StackTrace。

at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:601)
at android.support.v7.graphics.Palette.scaleBitmapDown(Palette.java:282)

如果您查看Palette.java的源代码,您会发现缩放逻辑写在方法scaleBitmapDown(Bitmap bitmap)中。如果您的“位图”小于100px,则不进行缩放。但是,如果您的“位图”大于100px,则调用Bitmap.createScaledBitmap()。现在,如果宽度或高度<0,则此方法会抛出IllegalArgumentException

因此,您传递的位图没有零宽度,因为如果是这种情况,您根本不会到达Bitmap.createScaledBitmap()方法。话虽如此,我不确定真正的原因是什么。尝试浏览您正在使用的确切Palette.java的源代码。


当我在 Android Studio 中点击粘贴的堆栈跟踪时,Palette 给我的代码略有不同,但确实具有您所看到的相同检查。我想,如果在检查和缩放之间发生了什么事情导致位图出现问题,那将是唯一的可能性。 - casolorz
我的猜测也是如此。崩溃是否发生在某个特定的设备或版本上?如果是这种情况,那么可能是操作系统版本代码有问题。但无论如何,我认为你对此无能为力。 - Henry

0
问题与并发问题有关: 由于您正在以“异步”方式使用Palette, 当您调用时
Palette.Builder(bitmap).generate(new Palette.PaletteAsyncListener()

你的位图是有效的,但当调色板在自己的异步逻辑中使用位图时,由于并发操作,位图可能为空或不再有效。

这个问题有一个简单的解决方法:由于你不需要高分辨率图像来提取关键颜色,所以只需提供从原始图像创建的低分辨率位图即可:

if( bitmap == null || bitmap.getHeight() <= 0 || bitmap.getWidth() <= 0){
   //do something
}else{
   //This resized bitmap is just an example: you should keep your bitmap
   //aspect ratio, and keep width and height < 100
   Bitmap resizedBitmap = Bitmap.createScaledBitmap(myBitmap, 100, 100, false); 
   Palette.Builder(resizedBitmap).generate(new Palette.PaletteAsyncListener() {
.....
}

有趣的想法,我会尝试一下。谢谢。 - casolorz
@mntgoat 别忘了在调整大小的位图中保持纵横比,否则可能会得到错误的关键颜色(我在示例中强制使用100x100像素)。 - bonnyz
是的,我是。实际上,我看到的Palette类的代码使用192作为最小值。 - casolorz
@mntgoat 你应该在宽度和高度上使用小于100像素的尺寸,以避免调色板创建额外的缩放/位图。 - bonnyz
我打算在悬赏到期之前授予您奖金,但我还不确定这是否是正确的答案。我将向我的测试用户发布它,如果几天内没有出现更多崩溃,那么我将把它标记为正确答案。 - casolorz

0
你可能正在尝试在UI元素实际添加到布局之前访问其宽度和高度。
这就是为什么你一直得到宽度和高度等于0的原因,因为该元素实际上并不存在。
使用ViewTreeObserverhttp://developer.android.com/reference/android/view/ViewTreeObserver.html
    myView.getViewTreeObserver().addOnPreDrawListener(
            new ViewTreeObserver.OnPreDrawListener() {
                public boolean onPreDraw() {

                        int finalHeight = myView.getMeasuredHeight();
                        int finalWidth = myView.getMeasuredWidth();
                        // Do your work here


                    return true;
                }
            });

其中myView将是您的位图


我并不是在尝试访问它,而是Palette类在访问。而且在调用Palette类之前,我会检查宽度、高度和空值。我无法更改Palette代码,那么我该如何确保这种情况不会发生? - casolorz
在TreeObserver内调用Palette类。这样,位图在调用调色板类之前就已经定义好了。 - Prasanth Louis
我实际上没有在调用调色板代码之前加载这些位图的视图。我在知道调色板颜色后将它们加载到视图中。这对大多数用户都有效,每天只有4或5个崩溃,而日活跃用户数为20k。 - casolorz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接