1

私はthquinnのDraggableGridViewを使用しており、そこに〜60枚の画像をロードしています。これはすべてうまくいきます。アセットに必要なすべての画像がありましたが、最初に画像のテキストのみが変更されるため、実行時にそれらを作成したいと考えています。追加は問題になりませんが、アセットからの削除は不可能であり、不要なスペースを使用する Air。ここで私の動機を簡単に説明します。

したがって、この投稿のメソッドを使用してアセット png にテキストを描画し、それをビットマップに変換して LRU キャッシュで使用できるようにしました。これはいくつかの画像で機能しますが、必要なすべての画像を表示しようとするとすぐに OutOfMemory エラーが発生します。ベース画像は 200x200 px で、画面サイズと密度に応じて必要なサイズにスケーリングする必要があると思います。
まず、ビットマップ キャンバスを作成してから、(キャッシュ用に) ビットマップにする LayerdDrawable を作成するため、この方法は効率的ではないようです。確かではありませんが、メモリを乱雑にする多くの一時画像を作成しているように感じます。そして、減価償却された BitmapDrawable を使用しています。BitmapDrawable がないと、このメソッドはどのように見えますか??

私はこれを一般的に正しい方法で行っていますか?また、OOMエラーが発生しないように、このメソッドを効率的に作成するにはどうすればよいですか?!?

ところで。LRUcache を使用せず、GridView の LayerdDrawable を返すだけの場合、画像は正常に読み込まれますが、オリエンテーションを数回変更した後に例外が発生します。これは私が持っている方法です:

private Bitmap createIcon(Drawable backgroundImage, String text,
                          int width, int height) {

    String key = text.toLowerCase();
    Bitmap cachedBitmap = getBitmapFromMemCache(key);

    if (cachedBitmap != null){
        Log.d("TRACE", "is cached");
        return cachedBitmap;
    }
    else{

        Bitmap canvasBitmap = Bitmap.createBitmap(width, height,
                Bitmap.Config.ARGB_8888);
        Canvas imageCanvas = new Canvas(canvasBitmap);

        Typeface font = Typeface.createFromAsset(getActivity().getAssets(), "myriadpro.ttf");

        Paint imagePaint = new Paint();
        imagePaint.setTextAlign(Paint.Align.CENTER);
        imagePaint.setTextSize(26);//
        imagePaint.setTypeface(font);
        imagePaint.setAntiAlias(true);
        imagePaint.setColor(Color.parseColor("#562b12"));
        backgroundImage.draw(imageCanvas);

        imageCanvas.drawText(text, (width / 2)+4, (height / 2)-8, imagePaint);

        LayerDrawable layerDrawable = new LayerDrawable(
                new Drawable[]{backgroundImage, new BitmapDrawable(canvasBitmap)});
        int w = layerDrawable.getIntrinsicWidth();
        int h = layerDrawable.getIntrinsicHeight();

        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        layerDrawable.draw(canvas);

        addBitmapToMemoryCache(key,bitmap);
        return bitmap;
    }
}

更新: BitmapDrawable を使用していないため、別の方法を試してみました。しかし、それでも OOM エラーが発生します。また、通常、キャッシュから取得した画像が 1 つまたは 2 つしかない場合に、キャッシュされた画像を実際に使用していないようです。

これがフラグメント内にある前に、私も言及できませんでした。それが重要かどうかはわかりません。しかし、縦向きモードではこのフラグメントしかなく、横向きモードでは幅が許せば別のフラグメントが存在する可能性があります。

public Bitmap drawTextToBitmap(Context mContext,  int resourceId,  String mText) {
    try {

        int memory = (int) (Runtime.getRuntime().freeMemory() / 1024);
        Log.d("TRACE", "memory " + memory);
        Log.d("TRACE", mText);

        String key = mText.toLowerCase();
        Bitmap cachedBitmap = getBitmapFromMemCache(key);

        if (cachedBitmap != null){
            Log.d("TRACE", "is cached");
            return cachedBitmap;
        }
        else{
        Resources resources = mContext.getResources();
        float scale = resources.getDisplayMetrics().density;
        Bitmap bitmap = BitmapFactory.decodeResource(resources, resourceId);

        android.graphics.Bitmap.Config bitmapConfig =   bitmap.getConfig();
        // set default bitmap config if none
        if(bitmapConfig == null) {
            bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
        }
         bitmap = bitmap.copy(bitmapConfig, true); // OOE error happens here

        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.rgb(110,110, 110));
        paint.setTextSize((int) (25 * scale));

        Rect bounds = new Rect();
        paint.getTextBounds(mText, 0, mText.length(), bounds);
        int x = (bitmap.getWidth() - bounds.width())/6;
        int y = (bitmap.getHeight() + bounds.height())/5;

        canvas.drawText(mText, x * scale, y * scale, paint);

        addBitmapToMemoryCache(key,bitmap);
        return bitmap;
        }
    } catch (Exception e) {
        // TODO: handle exception
        return null;
    }

}
4

1 に答える 1

0

私は常に 3 ~ 4 個の非常に大きな画像をメモリに保持する必要があるアプリに取り組んでいましたが、あなたと非常によく似た問題に苦しんでいました。バイト配列からビットマップをロードした後、それをコピーして変更可能にし、描画できるようにする必要がありました。このコピーにより、メモリ内のビットマップが多すぎて、OOM クラッシュが発生します。

最終的に、一度ロードし、同時に変更可能にする方法を見つけました。

Options options = new Options();
options.inMutable = true;
BitmapFactory.decodeResource(getResources(), id, options);

ビットマップをコピーして変更可能にする代わりに、これを使用します。ARGB_8888 構成が本当に必要かどうかはわかりませんが、必要ない場合は、少なくともメモリ効率が向上するはずです。

注: これは、Android 3.0 以降でのみ機能します。2.x 以降で実行する必要があるバージョンの場合、少しのリフレクション マジックを使用して、「inMutable」フィールドが実行時に存在するかどうかを確認できます。これは 3.0 より前のデバイスでは役に立ちませんが、ほとんどのデバイスでは改善されます (また、2.x を実行しているデバイスはメモリの柔軟性が高い傾向にあることにも気付きました)。

コードは次のとおりです。

Options options = new Options();
options.inPurgeable = true;
options.inInputShareable = true;

Bitmap mutableBitmap = null;

try
{
    Options.class.getField("inMutable").set(options, Boolean.TRUE);
    Bitmap decodedBitmap = BitmapFactory.decodeResource(getResources(), id, options);                       
    mutableBitmap = decodedBytes;

}
catch (NoSuchFieldException noFieldException)                       
{
    Bitmap decodedBitmap  = BitmapFactory.decodeResource(getResources(), id, options);                              
    mutableBitmap = decodedBitmap .copy(decodedBitmap .getConfig(), true);
    decodedBitmap .recycle();                                                       
}
于 2013-09-25T14:12:11.093 に答える