在为Honeycomb调用Activity以避免OOME时清除Gallery?

时间:2011-05-10 05:15:47

标签: android bitmap gallery android-3.0-honeycomb out-of-memory

我正在为Android 3.0 Honeycomb构建一个书籍查看器。它在三星Galaxy Tab上运行良好,但在3.0.1上的Motorola Xoom上获得了很多OutOfMemoryErrors。两个设备都有48MB的VM堆空间。

我有两项活动:

BookActivity - 有一个SlowGallery可以加载1280x640张图片,还有一个小图库可以加载160x80张图片。

SlowGallery是一个次要覆盖,可以让它一次投放一个图库项目,而不是快速滚动。

BitmapActivity - 只有一个ImageView可以加载4488x2244图像,还有一个小图库可以加载160x80图像。缩小图像尺寸不是一种选择,因为用户打算将图像放大到100%。

我把它放在Bitmap加载方法中,将位图缩减为16位:

BitmapFactory.Options o2 = new BitmapFactory.Options();
if (compressColor) o2.inPreferredConfig = Bitmap.Config.RGB_565;
o2.inPurgeable = true;
o2.inInputShareable = true;
o2.inSampleSize = (int) scale;
b = BitmapFactory.decodeStream(fis, null, o2);

当我双击BookActivity的图库时,它会调用BitmapActivity,传递要打开的相应图像编号。我可以这样做1-3次,输入BitmapActivity,然后在它遇到OutOfMemoryError之前单击Back。

在双击图库时,它会调用PageAdapter.purge(),它可以直观地卸载图库的图像。

这是BookActivity.PageAdapter,它是SlowGallery的适配器:

private class PageAdapter extends BaseAdapter {
private final LayoutInflater mInflater;
private Page currentPage;
private boolean purge = false;
private WeakReference<Bitmap> weakReferenceBitmap;
public PageAdapter(Context context) {
    mInflater = LayoutInflater.from(context);
}
public void unpurge() {
    purge = false;
    notifyDataSetChanged();
}   
public void purge() {
    purge = true;
    holder = null;
    notifyDataSetChanged();
}       
@Override
public int getCount() {
    if (listPages==null || purge) return 0;
    return listPages.size();
}
@Override
public Object getItem(int position) {
    return null;
}
@Override
public long getItemId(int position) {
    return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.gallery_pages, null);
        holder = new ViewHolderIssues();
        holder.image = (ImageView) convertView.findViewById(R.id.ImageViewPage);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolderIssues) convertView.getTag();
    }
    if (position < listPages.size()) {
        currentPage = listPages.get(position);
        File f = new File(Engine.PATH + currentPage.getImageMedium());
        if (!purge) {
            if (!f.exists()) {
                holder.image.setImageResource(R.drawable.loading);
                Engine.triggerTrickle(currentPage.getImageMedium(), WeightedAsset.IMAGE_MEDIUM, getApplicationContext());                   
            } else {
                weakReferenceBitmap = new WeakReference<Bitmap>(Engine.loadImageFromBitmap(currentPage.getImageMedium(), screenWidth, 1, true));
                if (weakReferenceBitmap.get()!=null) {
                    holder.image.setImageBitmap(weakReferenceBitmap.get());
                } else {
                    holder.image.setImageDrawable(null);
                }
            }
        } else {
            weakReferenceBitmap.clear();
            holder.image.setImageDrawable(null);
            holder = null;
            System.gc();
        }
        f = null;
    }
    return convertView;
}
}

查看HPROF文件,在Dominator Tree下,即使我在BookActivity.SlowGalleryBitmapActivity仍然存在。在BookActivity时,SlowGallery占用3.2-6.5MB(每张图片1.6MB)但在BitmapActivity中占用1.6MB(SlowGallery.LinearLayout.ImageView.BitmapDrawable = 1.6MB)。我该如何摆脱SlowGallery

2 个答案:

答案 0 :(得分:0)

啊,有点复杂的代码块。弱引用可能有所帮助,但一般来说,如果在适配器中使用ImageView,则在设置新位图之前,应该获取旧的位图,然后调用Bitmap.recycle()。您应该在destroy编辑时执行BitmapActivity。这应该是您需要的大部分内容。

答案 1 :(得分:0)

谢谢!我设法重构它来回收位图。但是,由于BitmapActivity.onCreateBookActivity.onDestroy之前被调用,因此画廊仍然存在。如果我确实调用了purge()函数,除了点击/选中的视图(由Gallery双击监听器保持活动之外)我将设法清除其中的大部分内容!)

然后我消灭了这个已经存在的画廊并放置了我自己的ImageView imageviewCurrentPage(和一个ImageView imageviewFlipperPage)并将它们放入和取出。完成动画后,imageviewFlipperPage会立即销毁,所以我保证最多只能加载2个位图。使用所选的,点击的视图等,Gallery可以使用五个视图。

我还添加了这个以进一步隔离内存使用情况:

<activity android:name=".BitmapActivity" android:process=":BitmapActivity" ...>

但是,它带来了复杂性,即静态类不会跨进程共享。因此,如果在BookActivity中我做了Engine.SESSION_ID = 5,其中SESSION_ID是静态的,我将无法在BitmapActivity的Engine.SESSION_ID中读取它。