いくつかのアクティビティで複数の大きな画像を使用するAndroidアプリを開発しています。各画像は約1280x800で、アクティビティごとにこれらの画像を約2〜4個ロードします。これらの画像は、デバイス上の個々のアプリに割り当てられるメモリの点で非常に大きいことに気付きましたが、java.lang.OutOfMemoryエラーが発生することなく、元の解像度で画像を表示するにはどうすればよいですか?これらの画像をフルサイズで画面に表示する必要があります(画面が画像よりも小さい場合、スケーリングはxmlによって自動的に行われます)。画像をサムネイルに縮小してメモリに保存するという解決策を見ましたが、それによって画像が元のサイズ/解像度を失うことはありませんか?ご協力いただきありがとうございます!
3 に答える
これについてできることがいくつかあります。
最初に思い浮かぶのは、1280x800 は (おそらく) 画面全体であるため、一度に 1 つずつ表示するだけでよいということです。あなたがそれをしている間、他の人を記憶に留めないでください。
それでも、ピクセルあたり 4 バイトの 1280x800 画像はわずか 4MB であり、最近のタブレットはすべて 48MB のヒープを提供しているようです。必要に応じて、いくつかをメモリに保持できるはずです。メモリが不足している場合は、リークしている可能性があります。DDMS で視聴している場合、アクティビティを変更するとメモリ使用量が増加し続けますか?
リークの一般的な原因は、ビットマップ自体です。それらを使い終わったら、必ず電話Bitmap#recycle
してください。
結局のところ、提供されたヒープ領域に収まらない場合はandroid:largeHeap="true"
、マニフェストのアプリケーション タグに追加することもできます。これにより、より多くのヒープ領域 (一部のデバイスでは最大 256MB) を提供するシステムが要求されます。ただし、これはデバイスによって異なり、一部のデバイスでは完全に無視されるため、最後の手段にする必要があります (元の Kindle Fire が思い浮かびます)。
を使用すると、総ヒープ領域がどれだけあるかを確認できますRuntime.getRuntime().maxMemory();
。詳細な説明については、この回答を参照してください。どれだけ使用しているかを確認するのは難しいですが、その獣に取り組みたい場合は、ここに説明があります.
最後に、画像を xml で指定するよりも良い方法で画像を読み込むことができる場合があります。この開発者ガイド ページを必ずお読みください。それらを xml に残す必要がある場合でも、イメージ アセットdrawable-hdpi
をdrawable-mdpi
単にdrawable
.
この記事では、ヒープ ダンプを作成し、Eclipse MAT を使用して分析する方法について詳しく説明しています。これにより、メモリ リークの可能性が最も高い容疑者をすばやく見つけることができます。
繰り返しますが、問題を適切に克服する方法のチュートリアルがある別の SO Question から見つけたこの素晴らしいリンクを紹介します。
BitmapFactory または関連するメソッドを使用して画像をロードする前に、画像をスケーリングする必要があります。
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
全体は、Android 開発者サイトのLoading Large Bitmaps Efficientlyで説明されています。