我正在使用thquinn’s DraggableGridView并加载~60张图片。一切正常。我拥有了我的资产中所需的所有图像,但是想要在运行时创建它们,因为只有图像上的Text更改,这似乎是多余的,我可以减少appsize,第二个原因是我需要有时更改图标添加不会成为问题的空气,但不能从资产中删除,并会使用不必要的空间。这简要地解释了我的动机。
所以我使用method from this Post在我的Asset png上绘制文本,然后将其转换为Bitmap,以便能够在LRUcache中使用它们。这适用于一些图像,但一旦我尝试显示所有需要的图像,我得到一个OutOfMemory错误。基本图像是200x200像素,我认为也应根据屏幕尺寸和密度调整到需要尺寸
首先,这个方法看起来效率不高,因为我创建了一个Bitmap画布,然后制作了一个LayerdDrawable,我再次将其制作成Bitmap(用于缓存)。不确定,但感觉就像我正在创造那些使记忆混乱的临时图像。
然后我使用折旧的BitmapDrawable。 如果没有BitmapDrawable,这个方法看起来怎么样?
我是否正确地采用了这种方法,如何有效地使用此方法,以免出现OOM错误?!
顺便说一句。当我不使用LRUcache并且只返回GridView的LayerdDrawable时,图像加载正常,但是在几次Orientation更改后我得到了Exception! 这就是我的方法:
private Bitmap createIcon(Drawable backgroundImage, String text,
int width, int height) {
String key = text.toLowerCase();
Bitmap cachedBitmap = getBitmapFromMemCache(key);
if (cachedBitmap != null){
Log.d("TRACE", "is cached");
return cachedBitmap;
}
else{
Bitmap canvasBitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
Canvas imageCanvas = new Canvas(canvasBitmap);
Typeface font = Typeface.createFromAsset(getActivity().getAssets(), "myriadpro.ttf");
Paint imagePaint = new Paint();
imagePaint.setTextAlign(Paint.Align.CENTER);
imagePaint.setTextSize(26);//
imagePaint.setTypeface(font);
imagePaint.setAntiAlias(true);
imagePaint.setColor(Color.parseColor("#562b12"));
backgroundImage.draw(imageCanvas);
imageCanvas.drawText(text, (width / 2)+4, (height / 2)-8, imagePaint);
LayerDrawable layerDrawable = new LayerDrawable(
new Drawable[]{backgroundImage, new BitmapDrawable(canvasBitmap)});
int w = layerDrawable.getIntrinsicWidth();
int h = layerDrawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
layerDrawable.draw(canvas);
addBitmapToMemoryCache(key,bitmap);
return bitmap;
}
}
更新 我现在尝试了另一种方法,这似乎更好,因为它不使用BitmapDrawable。但我仍然得到OOM错误。此外,它通常似乎不会真正使用缓存的图像,当我更改方向时,只有1或2个图像来自缓存。
在片段内部之前我也未提及。不确定是否重要。但是在纵向模式下我只有这个片段,而在景观中,如果宽度允许,可以有另一个片段。
public Bitmap drawTextToBitmap(Context mContext, int resourceId, String mText) {
try {
int memory = (int) (Runtime.getRuntime().freeMemory() / 1024);
Log.d("TRACE", "memory " + memory);
Log.d("TRACE", mText);
String key = mText.toLowerCase();
Bitmap cachedBitmap = getBitmapFromMemCache(key);
if (cachedBitmap != null){
Log.d("TRACE", "is cached");
return cachedBitmap;
}
else{
Resources resources = mContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap = BitmapFactory.decodeResource(resources, resourceId);
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
bitmap = bitmap.copy(bitmapConfig, true); // OOE error happens here
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.rgb(110,110, 110));
paint.setTextSize((int) (25 * scale));
Rect bounds = new Rect();
paint.getTextBounds(mText, 0, mText.length(), bounds);
int x = (bitmap.getWidth() - bounds.width())/6;
int y = (bitmap.getHeight() + bounds.height())/5;
canvas.drawText(mText, x * scale, y * scale, paint);
addBitmapToMemoryCache(key,bitmap);
return bitmap;
}
} catch (Exception e) {
// TODO: handle exception
return null;
}
}
答案 0 :(得分:0)
我在一个应用程序上工作,需要在内存中持续保存3-4个非常大的图像,我正在努力解决与你的问题非常相似的问题。我从字节数组加载了一个位图,然后我需要复制它以使其可变,以便我可以在它上面绘制。此副本会导致内存中有太多位图,然后导致OOM崩溃。
最终我找到了一种方法来加载它,同时使它变得可变:
Options options = new Options();
options.inMutable = true;
BitmapFactory.decodeResource(getResources(), id, options);
使用此方法,而不是复制位图以使其可变。我不确定你是否真的需要ARGB_8888配置,但如果你不这样做,这至少应该提高你的内存效率。
注意:这仅适用于Android 3.0及更高版本。对于需要在2.x及更高版本上运行的版本,您可以使用一点反射魔法来查看运行时是否存在“inMutable”字段。虽然这对3.0之前的设备没有帮助,但它仍然可以为大多数设备提供良好的改进(我还注意到运行2.x的设备往往具有更大的内存灵活性)。
以下是代码:
Options options = new Options();
options.inPurgeable = true;
options.inInputShareable = true;
Bitmap mutableBitmap = null;
try
{
Options.class.getField("inMutable").set(options, Boolean.TRUE);
Bitmap decodedBitmap = BitmapFactory.decodeResource(getResources(), id, options);
mutableBitmap = decodedBytes;
}
catch (NoSuchFieldException noFieldException)
{
Bitmap decodedBitmap = BitmapFactory.decodeResource(getResources(), id, options);
mutableBitmap = decodedBitmap .copy(decodedBitmap .getConfig(), true);
decodedBitmap .recycle();
}