【问题标题】:some problems with Android Bitmap in Out of MemoryAndroid Bitmap in Out of Memory 的一些问题
【发布时间】:2012-04-28 08:21:14
【问题描述】:

我创建了一个 ViewFlipper 以在单个活动中显示来自 Internet 的图像。投掷时,将图像设置为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();
}

这是加载图像的代码。

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));
}

【问题讨论】:

标签: android android-layout bitmap out-of-memory


【解决方案1】:

根据您的代码,您不使用 ImageCache 类的单例性质,每次调用 LoadImage(int n) 时都会创建新的 ImageCache 实例:

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

这真的很奇怪。改为使用:

imageCache = ImageCache.getInstance();

【讨论】:

  • 感谢您的关注,我已经注意到了这个问题。
【解决方案2】:

释放位图分配的内存的唯一方法是recycle()。你应该removeView(View) 不在[current - 1; current + 1] 范围内,然后recycle 你自己分配的位图。所有这些代码对我来说似乎都是多余的,而且调用 GC 也不是一个好主意。您可以将 InputStream 的内容保存在永久存储上,这样就不会产生网络开销。

【讨论】:

    【解决方案3】:

    您应该只加载并保存您需要的 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];
    }
    

    inSampleSize 设置为 > 1,请求解码器对原始图像进行二次采样,返回较小的图像以节省内存。
    使用 2 的幂可以提高效率。

    【讨论】:

      猜你喜欢
      • 2013-08-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 2019-06-18
      • 2020-09-24
      • 1970-01-01
      相关资源
      最近更新 更多