1

私は ViewFlipper を作成して、単一のアクティビティでインターネットから画像を表示します。フリングするときは、image を imageView に設定し、それを viewflipper に追加します。しかし、問題は、約 20 枚の画像を表示した後に常に OOM が発生することです。私はそれを解決するためにいくつかのきれいな仕事をしましたが、うまくいきませんでした! これがコードです。

public class ImageCache {

static private ImageCache cache;
private Hashtable<Integer, MySoftRef> hashRefs;
private ReferenceQueue<Bitmap> q;

private class MySoftRef extends SoftReference<Bitmap> {
    private Integer _key = 0;

    public MySoftRef(Bitmap bmp, ReferenceQueue<Bitmap> q, int key) {
        super(bmp, q);
        _key = key;
    }
}


public ImageCache() {
    hashRefs = new Hashtable<Integer, MySoftRef>();
    q = new ReferenceQueue<Bitmap>();
}

public static ImageCache getInstance() {
    if (cache == null) {
        cache = new ImageCache();
    }
    return cache;
}

private void addCacheBitmap(Bitmap bmp, Integer key) {
    cleanCache();
    MySoftRef ref = new MySoftRef(bmp, q, key);
    hashRefs.put(key, ref);
}

public Bitmap getBitmap(int resId) {
    Bitmap bmp = null;
    if (hashRefs.containsKey(resId)) {
        MySoftRef ref = (MySoftRef) hashRefs.get(resId);
        bmp = (Bitmap) ref.get();
    }

    if (bmp == null) {
        URL imgUrl = null;
        try {
            imgUrl = new URL("http:/example/images/" + resId
                    + ".jpg");
            HttpURLConnection conn = (HttpURLConnection) imgUrl
                    .openConnection();
            conn.connect();
            InputStream is = conn.getInputStream();
            bmp  = BitmapFactory.decodeStream(is);
            is.close();
            addCacheBitmap(bmp, resId);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    return bmp;
}

private void cleanCache() {
    MySoftRef ref = null;
    while ((ref = (MySoftRef) q.poll()) != null) {
        hashRefs.remove(ref._key);
    }
}

public void clearCache() {
    cleanCache();
    hashRefs.clear();
    System.gc();
    System.runFinalization();
}

これがloadimageコードです。

public void LoadImage(int n){
    iv = new ImageView(this);
    imageCache = new ImageCache();
    Bitmap bm = imageCache.getBitmap(n);
    iv.setImageBitmap(bm);
    iv.setScaleType(ImageView.ScaleType.CENTER);
    viewFlipper.addView(iv, new LayoutParams(LayoutParams.FILL_PARENT,
            LayoutParams.FILL_PARENT));
}
4

3 に答える 3

0

Bitmap で割り当てられたメモリを解放する唯一の方法は、recycle(). それがremoveView(View)範囲内にない場合は、自分で割り当てたビットマップです。そのコードはすべてやり過ぎに思えますし、GC を呼び出すのも得策ではありません。InputStream の内容を永続ストレージに保存できるため、ネットワークのオーバーヘッドは発生しません。[current - 1; current + 1]recycle

于 2012-04-28T08:36:11.853 に答える
0

必要な 3 つのイメージのみをロードしてキャッシュに保持する必要があります。

  • 前の画像
  • 現在のもの
  • 次のもの

他の人の記憶を解放するだけです。そのためにrecycle()関数を使用します。
必要に応じて、5 つの画像を保持することもできます。しかし、それらすべてを保持する必要はありません。

アプリケーションをリアクティブにしたい場合は、サムネイルをメモリに保持して表示し、画像に x 秒以上留まっている場合にのみ完全な画像を読み込むことができます。

小さい画像を作成し、ビットマップのリストを管理するコードは次のとおりです。

Options mThumbOpts = new Options();
mThumbOpts.inSampleSize = 4;

/** The fonction to get a Bitmap from the list */
private Bitmap getBitmap(int id) {
    // TODO recycle previous/next bitmaps here (id -2 and id +2 if they exist)

    // Reload the image if necessary
    if (bitmapList[id] == null || bitmapList[id].isRecycled()) {
        bitmapList[id] = BitmapFactory.decodeFile(imagePath, mThumbOpts);
    }
    return bitmapList[id];
}

値 > 1 に設定されたinSampleSizeは、元のイメージをサブサンプリングするようデコーダに要求し、メモリを節約するためにより小さいイメージを返します。
より効率的にするには、2 のべき乗を使用します。

于 2012-04-28T08:38:25.123 に答える
0

クラスのシングルトンの性質を使用しないコードによると、呼び出されるたびにImageCache新しいインスタンスを作成します。ImageCacheLoadImage(int n)

imageCache = new ImageCache();
Bitmap bm = imageCache.getBitmap(n);

これは本当に奇妙です。代わりに使用してください:

imageCache = ImageCache.getInstance();
于 2012-04-28T08:43:25.000 に答える