13

drawable フォルダーに高解像度の画像 (2588*1603) があります。以下のコード (1) を使用して imageView に設定すると、OOM 例外が発生せず、イメージが期待どおりに割り当てられます。

public class MainActivity extends ActionBarActivity{


    private ImageView mImageView;

    int mImageHeight = 0;
    int mImageWidth  = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

      mImageView = (ImageView) findViewById(R.id.imageView);
      mImageView.setScaleType(ScaleType.FIT_CENTER);

      BitmapFactory.Options sizeOption = new BitmapFactory.Options();
      sizeOption.inJustDecodeBounds = true;
      BitmapFactory.decodeResource(getResources(), R.drawable.a, sizeOption);
      mImageHeight = sizeOption.outHeight;
      mImageWidth  = sizeOption.outWidth; 

      mImageView.post(new Runnable() {
          @Override
          public void run() {
              try {
                BitmapRegionDecoder bmpDecoder = BitmapRegionDecoder
                          .newInstance(getResources().openRawResource(R.drawable.a),true);
            Rect rect = new Rect(0,0,mImageWidth, mImageHeight);
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
            options.inDensity = getResources().getDisplayMetrics().densityDpi;
            Bitmap bmp = bmpDecoder.decodeRegion(rect, options);

            mImageView.setImageBitmap(bmp);  

            } catch (NotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }   
          }
      });

    }
}

rect サイズは画像サイズとまったく同じであることに注意してください。

しかし、たとえば 2 または 3 のような他の方法を使用すると、OOM が発生します。

  2)  mImageView.setBackgroundResource(R.drawable.a);

  3) Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.a);
     mImageView.setImageBitmap(bmp);

1 と 2,3 はどう違いますか?

(OOMの解決方法は知っていますが、違いを知りたいだけです)

4

4 に答える 4

2

これはのソースですBitmapRegionDecoder#decodeRegion

public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
    checkRecycled("decodeRegion called on recycled region decoder");
    if (rect.left < 0 || rect.top < 0 || rect.right > getWidth()
            || rect.bottom > getHeight())
        throw new IllegalArgumentException("rectangle is not inside the image");
    return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
            rect.right - rect.left, rect.bottom - rect.top, options);
}

ご覧のとおり、ネイティブ メソッドを呼び出すだけです。inDensityメソッドが(フラグに従って)ビットマップを縮小するかどうかを確認するのに十分なC++を理解していません。

他の 2 つのメソッドは、同じネイティブ メソッド ( nativeDecodeAsset) を使用してビットマップを取得します。

番号 2はドローアブルをキャッシュするため、より多くのメモリが必要です。
多くの操作 (ビットマップが既にプリロードまたはキャッシュされているかどうかの確認など) の後、ネイティブ メソッドを呼び出してビットマップを取得します。次に、ドローアブルをキャッシュし、背景画像を設定します。

番号 3 は非常に簡単です。いくつかの操作の後にネイティブ メソッドを呼び出します。


結論:ここでどのシナリオが当てはまるかはわかりませんが、この 2 つのいずれかである必要があります。

  1. 最初の試行では、ビットマップ (inDensityフラグ) が縮小されるため、必要なメモリが少なくなります。
  2. 3 つの方法はすべて、多かれ少なかれ同じ量のメモリを必要とし、2 番目と 3 番目の方法は少し多くなります。イメージは最大 16MB の RAM を使用します。これは、一部の電話の最大ヒープ サイズです。番号 1 はその制限を下回っている可能性がありますが、他の 2 つはしきい値をわずかに上回っています。

この問題をデバッグすることをお勧めします。マニフェストで、android:largeHeap="true"より多くのメモリを取得するように設定します。次に、3 つの異なる試行を実行し、ビットマップによって割り当てられたヒープ サイズとバイト数をログに記録します。

long maxMemory = Runtime.getRuntime().maxMemory();
long usedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
long freeMemory = maxMemory - usedMemory;
long bitmapSize = bmp.getAllocationByteCount();

これにより、より良い概要が得られます。

于 2015-05-06T10:58:08.880 に答える
-1

画像の詳細が多すぎると、メモリ不足になります。

概要: 1 スケーリングされたビットマップを使用します。2,3詳細なドローアブル全体をロードし(これによりメモリ不足になります)、サイズを変更してimageviewに設定します。

1

Bitmap bmp = bmpDecoder.decodeRegion(rect, options);

コンストラクター(InputStream is、boolean isShareable)は stream を使用しますが、これはメモリを使い果たしません。

BitmapFactory.Options を使用すると、BitmapRegionDecoder はビットマップを縮小します。

参照: BitmapRegionDecoder は、要求されたコンテンツを提供されたビットマップに描画し、出力コンテンツ サイズ (ポスト スケーリング) が提供されたビットマップよりも大きい場合はクリッピングします。提供されたビットマップの幅、高さ、および Bitmap.Config は変更されません

2,3

Drawable d = mContext.getDrawable(mResource);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.a);

スケール オプションはありません。画像全体がメモリにロードされます。

英語で申し訳ありません。

多分あなたを助けます。

于 2015-05-04T08:56:24.857 に答える