web-dev-qa-db-ja.com

高解像度画像-OutOfMemoryError

GalaxyS4用のアプリケーションを開発しています。アプリケーションの要件の1つは、1920x1080ピクセルの画像を含むSplashScreenを用意することです。その高品質の.jpeg画像と画像のサイズは約2メガバイトです。

問題は、アプリケーションを起動するとすぐにOutOfMemoryErrorが発生することです。サイズがわずか2メガバイトの画像でこれがすでに発生していることに私は非常に驚いていますか? この問題を修正して画像を表示するにはどうすればよいですか?

画像のサイズやサイズを変更することはできません。

SplashScreen.Java

public class Splashscreen extends Activity {

private static final int SPLASH_DURATION = 2000;
private boolean isBackPressed = false; 

@Override
protected void onCreate(Bundle savedInstanceState) {

    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(LayoutParams.FLAG_FULLSCREEN, LayoutParams.FLAG_FULLSCREEN);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.splashscreen);

    Handler h = new Handler();

    h.postDelayed(new Runnable() {

        @Override
        public void run() {

            // check if the backbutton has been pressed within the splash_duration
            if(!isBackPressed) { 

                Intent i = new Intent(Splashscreen.this, MainActivity.class);
                i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                Splashscreen.this.startActivity(i);
                overridePendingTransition(R.anim.short_fade_in, R.anim.short_fade_out);
            }       

            finish();
        }
    }, SPLASH_DURATION);
}

@Override
public void onBackPressed() {

    isBackPressed = true;
    super.onBackPressed();
}
}

そしてsplashscreen.xml

    <ImageView 
        xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:id="@+id/ivSplashScreenImage"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent" 
        Android:scaleType="fitXY"
        Android:src="@drawable/high_res_splashscreen_image"/>

追加情報:

時々(多くのデバイスメモリが利用可能な場合)、アプリはスプラッシュ画面を通過することができますが、アプリのメモリ消費量は非常識です(約100メガバイト)。 SplashScreenアクティビティを閉じてfinish()しましたが、ImageView /メモリに保持されている画像への参照があるようです。

どうすれば膨大なメモリ消費を削減できますか?

スプラッシュ画面を表示しない場合、アプリは約35MBのメモリしか消費しません。 SplashScreenイメージでは、約100MBです。

15
Philipp Jahoda

あなたを助けるべき3つのヒント:

  1. これを使用して、画像をロードします。 大きなビットマップのロードAndroidドキュメント

    _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);
    }
    
    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) {
    
            // Calculate ratios of height and width to requested height and width
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
    
            // Choose the smallest ratio as inSampleSize value, this will guarantee
            // a final image with both dimensions larger than or equal to the
            // requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
    
        return inSampleSize;
    }
    _
  2. Bitmapのインスタンスがメモリに1つしかないことを確認してください。表示した後、recycle()を呼び出し、参照をnullに設定します。 Memory Allocation Tracker を使用して、何が割り当てられているかを確認できます。コメントで提案されているように、HPROFファイルを読み取ることもできます。

  3. デフォルトでは、_ARGB_8888_ピクセル形式が使用されます。これは、ピクセルあたり4バイトを意味します。非常に良い記事: ビットマップの品質、バンディング、ディザリング 。画像はJPEGであるため、透明度がないため、アルファチャネルのすべてのピクセルで1バイトを浪費しています。可能性はそれほど高くありませんが、許容できる品質であれば、さらに経済的な形式を使用できます。 取る それらを見てください。たぶん_RGB_565_など。ピクセルに2バイトかかるため、画像は50%明るくなります。ディザリングを有効にして、_RGB_565_の品質を向上させることができます。

14

私も同様の問題を抱えていましたが、解決策は簡単です。高解像度の1920x1080ピクセルの画像をdrawable-nodpiディレクトリに配置します。 システムは、現在の画面の密度に関係なく、この修飾子でタグ付けされたリソースをスケーリングしないため、OutOfMemoryErrorが発生するため、問題は解消されます。

Androidドキュメント: http://developer.Android.com/intl/es/guide/practices/screens_support.html を確認してください

それが役に立てば幸い。

6