Утечка памяти Android bitmap imageview
я помещаю 4x4 imageView в действие (BoardActivity), и пользователь может изменить изображения, щелкнув их. С HTC Desire (Android 2.2.2) я получил OOM(из памяти) примерно за 30 минут интенсивного использования -EDIT: 16-е начало этой деятельности -, но никакие другие устройства не производят это (android 2.1 и android 2.2.1). Возможно ли, что я допустил ошибку с использованием bitmap/imageview и это вызывает эту ошибку? Сначала я загружаю весь идентификатор ресурса в a карта:
private Map<String, Integer> imageResourceMap;
imageResourceMap = new HashMap<String, Integer>();
imageResourceMap.put("a", R.drawable.a);
imageResourceMap.put("b", R.drawable.b);
imageResourceMap.put("c", R.drawable.c);
//... I store 55 drawable's resourceId in this map
затем я изменяю размер и сохраняю каждое изображение в растровое изображение, представленное на карте:
private static Map<String, Bitmap> imageBitmap;
private void loadBitmaps(int imagesSize) {
for (String s : imageResourceMap.keySet()) {
Bitmap tmp = getBitmapFromRes(imageResourceMap.get(s), imagesSize);
imageBitmap.put(s, tmp);
}
}
private Bitmap getBitmapFromRes(int resId, int imageSize) {
Bitmap b = null;
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
InputStream fis = getResources().openRawResource(resId);
BitmapFactory.decodeStream(fis, null, o);
fis.close();
int scale = 1;
if (o.outHeight > imageSize || o.outWidth > imageSize) {
scale = (int) Math.pow(2, (int) Math.round(Math.log(imageSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
fis = getResources().openRawResource(resId);
b = BitmapFactory.decodeStream(fis, null, o2);
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
return b;
}
я сохраняю imageViews в массиве и init все изображения с этой функцией:
private static ImageView[][] imageViews;
private ImageView getImage(String name) {
MyImageView item = new MyImageView(this, i, j, c + "");
item.setImageBitmap(imageBitmap.get(name));
item.setAdjustViewBounds(true);
return item;
}
когда мне нужно изменить изображение, я просто меняю его ресурс:
imageViews[i][j].setImageBitmap(imageBitmap.get("a"));
и прямо перед тем, как я закончу работу, я перерабатываю растровую карту:
private void recycleImageBitmaps() {
for (Bitmap b : imageBitmap.values()) {
if (b != null) {
b.recycle();
}
}
}
В AndroidManifest.xml I объявил это действие "singleTask":
<activity android:name=".game.board.BoardActivity" android:launchMode="singleTask">
</activity>
в этом приложении (игре) мы повторно открываем эту деятельность несколько раз... Что я сделал не так? Может ли это вызвать ошибку Out of Memory?
коррекция Исправлено getBitmapFromRes следующим образом:
private Bitmap getBitmapFromRes(int resId, int imageSize) {
Bitmap tmp = null;
Bitmap b = null;
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
InputStream fis = getResources().openRawResource(resId);
tmp = BitmapFactory.decodeStream(fis, null, o);
fis.close();
int scale = 1;
if (o.outHeight > imageSize || o.outWidth > imageSize) {
scale = (int) Math.pow(2, (int) Math.round(Math.log(imageSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
fis = getResources().openRawResource(resId);
b = BitmapFactory.decodeStream(fis, null, o2);
fis.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(tmp != null){
tmp.recycle();
tmp = null;
}
}
return b;
}
HTC все еще разбился в 11-м начале этой деятельности.
EDIT: Это действие (BoardActivity) запускается из действия (MenuActivity), которое имеет 4 imageButton и находится в Деятельность Tabhost. Объявления imageButtons выглядят следующим образом:
<ImageButton
android:id="@+id/game_menu_CreateButton"
android:layout_width="120dip"
android:layout_height="120dip"
android:layout_alignRight="@+id/textView1"
android:layout_alignTop="@+id/textView1"
android:background="@drawable/create"
android:layout_marginRight="1sp"
android:layout_marginTop="10sp"
/>
когда я запускаю BoardActivity из MenuActivity, я не вызываю finish()
при Менуактивности, и когда я звоню finish()
в BoardActivity я не начинаю новое намерение, поэтому он просто возвращается к уже открытой MenuActivity. И 16 раундов этого, я получил ум.
1 ответов
чтобы уменьшить память, вы можете попробовать эти вещи :
- после преобразования чертежей в растровые изображения можно задать imageResourceMap значение null. Это разгрузит 3 drawables.
- избегайте хранения ссылки на imageViews. Вы можете хранить imageViews даже после их удаления из пользовательского интерфейса
- утилизация растровых изображений чаще. Вместо того, чтобы просто onDestroy, как только вы знаете, что одно растровое изображение не используется, Вы можете переработать он.
Edit: на основе разговора в комментариях: растровое изображение, возвращаемое BitmapFactory.decodeStream (fis, null, o) не присваивается какой-либо переменной и, следовательно, не рециркулируется. Android 2.2 и 2.3 будут утечки в этой линии.