位图创建和绘制速度变慢......而且速度很快

时间:2018-02-16 21:31:32

标签: android performance bitmap drawing

这在很大程度上是一个问题(因为我不明白为什么会产生影响),并且在很大程度上有一篇帖子可以帮助其他一些可怜的程序员。

我有一个代码库,我在大约5-7年前首次启动Android编程时编写,它具有将文件读入内存的功能(用于许多事情),以及一个加载的函数来自.png文件的位图。后一个函数使用"读取文件"函数将文件中的字节读入字节数组,然后从中创建一个Bitmap。我知道这不是非常干净的代码,也不是最好的方法,但是它有效,为什么有些东西可以用呢?

除了...... Android的最后几个转速(特别是Oreo)导致我的应用程序中的绘图(来自位图)真的减慢了WAYYYYYY。我挣扎了好几天,试图弄清楚发生了什么,最后偶然发现了一个我不明白的修复工具。

这是"加载.png文件到Bitmap"的核心。功能(原样)。请注意整个" if-for-for"透明度的东西可能完全被忽略,它是将一种或两种颜色的像素转换成透明像素的特殊情况。在进入此块时,.png文件已被读入'位'。

BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inPreferredConfig = Bitmap.Config.valueOf("ARGB_8888");
Bitmap imbm = BitmapFactory.decodeByteArray(bits, 0, flen, bfo);// this makes an IMmutable bitmap
bits = null;
System.gc();
Bitmap bm = imbm.copy(Bitmap.Config.valueOf("ARGB_8888"), true);// convert it to a MUTABLE bitmap
imbm.recycle();
imbm = null;
w = bm.getWidth();
h = bm.getHeight();
// do transparency stuff
if (transX1 >= 0 && transX1 < w && transY1 >= 0 && transY1 < h) {
    clr1 = bm.getPixel(transX1, transY1);
    clr2 = bm.getPixel(transX2, transY2);
    for (y = 0; y < h; y++) {
        for (x = 0; x < w; x++) {
            clr = bm.getPixel(x, y);
            // convert any 0x00818181 (middle-gray) pixels to 0x00808080
            // so that 0x00818181 is guaranteed to never be used in customer-created bitmaps
            if (clr1 != 0xFF818181 && clr == 0xFF818181) bm.setPixel(x, y, 0xFF808080);
            else if (clr == clr1 || clr == clr2) bm.setPixel(x, y, clr & 0x00000000);
        }
    }
}
System.gc();    // request garbage-collection to try to avoid out-of-memory when loading/creating bitmap
return bm;

然后使用返回的Bitmap作为源,使用dC.drawBitmap(bm,sRect,dRect,kPaint)从中创建上下文。但是,Android的变化导致这种情况变慢。该修复原来是取代最终的&#34;返回bm&#34;上面有这段代码:

Bitmap tBM = Bitmap.createBitmap(w, h, Bitmap.Config.valueOf("ARGB_8888"));
Rect sRect = new Rect();
Rect dRect = new Rect();
sRect.set(0, 0, w, h);
dRect.set(0, 0, w, h);
Canvas dC = new Canvas(tBM);
dC.drawBitmap(bm, sRect, dRect, kPaint);
dC = null;
bm = null;
return tBM;

换句话说,它只需要&#39;&#39;由先前版本产生的位图创建了另一个相同大小的位图,绘制了&#39; bm&#39;进入新的Bitmap,并返回新的Bitmap而不是之前的版本。

关于以前构建Bitmap的方式的一些看起来似乎将它留在了一个糟糕的形式&#34;这使得绘制它非常慢,而在其中执行createBitmap()和drawBitmap()会产生一个可以非常快速地绘制的位图。

为什么会有这样的想法? (是的,我尝试了所有常用的RGB_565等等)。这种方法效果很好。但如果我理解为什么会发生这种情况,那就好了,就像我说的那样,我的艰辛可能对未来的某些人有用。

1 个答案:

答案 0 :(得分:0)

我怀疑减速是由decodeByteArray()(某种程度)引起的。

首先,通过更多研究(以及高级年龄和知识),我意识到通过设置BitmapFactory.Options.inMutable = true可以更容易地修复不可变/可变问题。

但是,问题的真正解决方案是改变核心&#39;代码:

BitmapFactory.Options   bfo = new BitmapFactory.Options();
bfo.inPreferredConfig = Bitmap.Config.valueOf("ARGB_8888");
bfo.inMutable = true;   // this makes an mutable bitmap
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    bfo.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
}
Bitmap  bm = BitmapFactory.decodeByteArray(bits, 0, flen, bfo);
bits = null;

换句话说,我摆脱了如上所述的不可变/可变位图副本,然后我测试在Oreo或更高版本上运行,如果是,则设置inPreferredColorSpace成员。这是在Oreo(API 26)中添加的。我想当他们添加类似的东西时,它会被设置为合理的默认值,而且我想是的,只是没有一个能够很好地将位图绘制到显示器上。默认值为&#39; null&#39;,但将其更改为SRGB足以使我从生成的Bitmap中快速绘制到显示中,因此我假设(总是危险的)此颜色空间问题正在变得越来越我在原帖中所做的位图的kludge副本理顺了。