私はアンドロイドアプリケーションで作業しています。アプリケーションには、多数のイメージを含むビューがあります。私は間違いがあったので、できるだけ多くの情報を提供しようとします。ビットマップを避けるための提案メモリ不足エラー
アプリケーションは、すべてのローカルテストでうまく機能していました。しかし、私は、ユーザーからのクラッシュの多くを受け取っ:java.lang.OutOfMemoryError: bitmap size exceeds VM budget
これが私の最大の問題は、私も古いデバイス上でローカルに問題を再現することができなかったということであるスタックトレース
0 java.lang.OutOfMemoryError: bitmap size exceeds VM budget
1 at android.graphics.Bitmap.nativeCreate(Native Method)
2 at android.graphics.Bitmap.createBitmap(Bitmap.java:507)
3 at android.graphics.Bitmap.createBitmap(Bitmap.java:474)
4 at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:379)
5 at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:498)
6 at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:473)
7 at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
8 at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:359)
9 at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:385)
です。
私はこの問題を解決しようとするものの多くを実装している:いいえメモリはをリークしない
- :私はまったくメモリリークがないことを確認しました。私はそれらを必要としないときに私はビューを削除しました。また、すべてのビットマップをリサイクルし、ガベージコレクタが正常に動作していることを確認しました。そして、私は
onDestroy()
メソッドのすべての必要な手順を実装しました - 画像サイズは正しく調整されました:画像を取得する前に、私は
inSampleSize
を計算します。 - ヒープサイズ:イメージを取得する前に最大ヒープサイズを検出し、十分なスペースがあることを確認します。十分でない場合は、それに応じて画像のサイズを変更します。
コード古いデバイス
のヒープサイズに基づいて画像のサイズを計算するために、ビットマップ// decodes image and scales it to reduce memory consumption
private static Bitmap decodeFile(File file, int newWidth, int newHeight)
{// target size
try
{
Bitmap bmp = MediaStore.Images.Media.getBitmap(getContext().getContentResolver(), Uri.fromFile(file));
if(bmp == null)
{
// avoid concurrence
// Decode image size
BitmapFactory.Options option = new BitmapFactory.Options();
// option = getBitmapOutput(file);
option.inDensity = res.getDisplayMetrics().densityDpi < DisplayMetrics.DENSITY_HIGH ? 120 : 240;
option.inTargetDensity = res.getDisplayMetrics().densityDpi;
if(newHeight > 0 && newWidth > 0)
option.inSampleSize = calculateInSampleSize(option, newWidth, newWidth);
option.inJustDecodeBounds = false;
byte[] decodeBuffer = new byte[12 * 1024];
option.inTempStorage = decodeBuffer;
option.inPurgeable = true;
option.inInputShareable = true;
option.inScaled = true;
bmp = BitmapFactory.decodeStream(new FileInputStream(file), null, option);
if(bmp == null)
{
return null;
}
}
else
{
int inDensity = res.getDisplayMetrics().densityDpi < DisplayMetrics.DENSITY_HIGH ? 120 : 240;
int inTargetDensity = res.getDisplayMetrics().densityDpi;
if(inDensity != inTargetDensity)
{
int newBmpWidth = (bmp.getWidth() * inTargetDensity)/inDensity;
int newBmpHeight = (bmp.getHeight() * inTargetDensity)/inDensity;
bmp = Bitmap.createScaledBitmap(bmp, newBmpWidth, newBmpHeight, true);
}
}
return bmp;
}
catch(Exception e)
{
Log.e("Error calling Application.decodeFile Method params: " + Arrays.toString(new Object[]{file }), e);
}
return null;
}
コードを取得するには、正しいinSampleSize
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;
}
コードを計算します
private void calculateImagesSize() { // only for android older than HoneyComb that does not support large heap if(Build.VERSION.SDK_INT < Constants.HONEYCOMB) { long maxHeapSize = Runtime.getRuntime().maxMemory(); long maxImageHeap = maxHeapSize - 10485760; if(Application.getResource().getDisplayMetrics().densityDpi >= DisplayMetrics.DENSITY_XHIGH) { maxImageHeap -= 12 * 1048576; } if(maxImageHeap < (30 * 1048576)) { int screenHeight = Math.min(Application.getResource().getDisplayMetrics().heightPixels, Application.getResource() .getDisplayMetrics().widthPixels); long maxImageSize = maxImageHeap/100; long maxPixels = maxImageSize/4; long maxHeight = (long) Math.sqrt(maxPixels/1.5); if(maxHeight < screenHeight) { drawableHeight = (int) maxHeight; drawableWidth = (int) (drawableHeight * 1.5); } } } }
私はこの問題がヒープだと思っています。たぶんosはアプリケーションがmaxheapsizeを使用できないことがあります。私の最大の問題は、問題を再現することができなかったことです。そのため、修正プログラムを試すときに、ユーザーが引き続きエラーを受けているかどうかを確認する必要があります。
メモリの問題が発生しました。どんな提案も大歓迎です。おかげでたくさん
非常に大きな画像を1つ取り、コードで使用してみてください。私はそれがクラッシュすると思う) 私はこの行が好きではない:ビットマップbmp = MediaStore.Images.Media.getBitmap(getContext()。getContentResolver()、Uri.fromFile(file)); – Leonidos
私は別の質問で提案の要約を書いた:http://stackoverflow.com/questions/11820266/android-bitmapfactory-decodestream-out-of-memory-with-a-400kb-file-with-2mb-f/16528487 #16528487 –
@Youssef、私はあなたがこれを見てみるべきだと思います - http://stackoverflow.com/a/15380872/1433187 私はメモリエラーから抜け出していました。 – Khobaib