这在很大程度上是一个问题(因为我不明白为什么会产生影响),并且在很大程度上有一篇帖子可以帮助其他一些可怜的程序员。
我有一个代码库,我在大约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等等)。这种方法效果很好。但如果我理解为什么会发生这种情况,那就好了,就像我说的那样,我的艰辛可能对未来的某些人有用。
答案 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副本理顺了。