在调用 Honeycomb 活动时清除 Gallery 以避免 OOME?

发布于 2024-11-06 02:37:53 字数 3557 浏览 0 评论 0原文

我正在为 Android 3.0 Honeycomb 构建一个图书查看器。它在 Samsung Galaxy Tab 上运行良好,但在 Motorola Xoom 3.0.1 上出现大量 OutOfMemoryErrors。两个设备都有 48MB VM 堆空间。

我有 2 个活动:

BookActivity - 有一个加载 1280x640 图像的 SlowGallery 和一个加载 160x80 图像的小图库。

SlowGallery 是一个较小的覆盖,使其一次弹出一个画廊项目,而不是快速滚动。

BitmapActivity - 有一个加载 4488x2244 图像的 ImageView 和一个加载 160x80 图像的小 Gallery。减小图像尺寸不是一个选项,因为用户打算将图像放大到 100%。

我将其放入位图加载方法中,以将位图减少到 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 的 Gallery 时,它会调用 BitmapActivity,并传递要打开的相应图像编号。我可以执行此操作 1-3 次,进入 BitmapActivity,然后单击“后退”,然后再遇到 OutOfMemoryError。

双击图库时,它会调用 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下,即使我在BitmapActivity中,BookActivity.SlowGallery似乎仍然存在。在 BookActivity 中,SlowGallery 占用 3.2-6.5MB(每个图像 1.6MB),但在 BitmapActivity 中占用 1.6MB(SlowGallery.LinearLayout.ImageView.BitmapDrawable = 1.6MB)。如何摆脱 SlowGallery

I am building a book viewer for Android 3.0 Honeycomb. It has been working fine on the Samsung Galaxy Tab but gets a lot of OutOfMemoryErrors on the Motorola Xoom on 3.0.1. Both devices have 48MB VM heap space.

I have 2 activities:

BookActivity - has a SlowGallery which loads 1280x640 images and a small Gallery which loads 160x80 images.

The SlowGallery is a minor override to make it fling one gallery item at a time instead of scrolling quickly.

BitmapActivity - has a single ImageView which loads an 4488x2244 image and a small Gallery which loads 160x80 images. Reducing the size of the image is not an option because the user is intended to enlarge the image to 100%.

I put this in the Bitmap-loading method to reduce the bitmap to 16-bit:

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

When I double-tap the BookActivity's Gallery, it calls BitmapActivity, passing the respective image number to be opened. I can do this 1-3 times, entering the BitmapActivity, then clicking Back, before it hits an OutOfMemoryError.

On double-tapping the Gallery it calls PageAdapter.purge(), which appears to visually unload the gallery's images.

This is BookActivity.PageAdapter, which is the adapter for the 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;
}
}

Looking at the HPROF file, under the Dominator Tree, it appears that the BookActivity.SlowGallery still exists even when I am in BitmapActivity. When in BookActivity, SlowGallery takes up 3.2-6.5MB (1.6MB per image) but in BitmapActivity it takes up 1.6MB (SlowGallery.LinearLayout.ImageView.BitmapDrawable = 1.6MB). How do I get rid of SlowGallery?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一花一树开 2024-11-13 02:37:53

啊,那里有相当复杂的代码块。弱引用可能会有所帮助,但一般来说,如果在适配器中使用 ImageView,则在设置新位图之前,您应该获取旧位图,然后调用 Bitmap.recycle()。您还应该在 BitmapActivity 被销毁时执行此操作。这应该可以满足您的大部分需求。

Ah, kinda complex chunk of code there. The weak references may help, but in general, if using an ImageView in an adapter, before you set the new bitmap you should fetch the old Bitmap and then call Bitmap.recycle(). You should also do that your BitmapActivity when it is destroyed. That should do most of what you need.

饮惑 2024-11-13 02:37:53

谢谢!我已经设法重构它以回收位图。但是,图库仍然存在,因为 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 中读取它。

Thanks! I've managed to refactor it to recycle the bitmap. However, the gallery was still sticking around because BitmapActivity.onCreate gets called before BookActivity.onDestroy. If I did call the purge() function I would manage to clear most of it except for the clicked/selected view (kept alive by the Gallery double-tap listener!)

I then wiped out the darned gallery and put my own ImageView imageviewCurrentPage (and a ImageView imageviewFlipperPage) and animated them in and out. The imageviewFlipperPage would be destroyed immediately when the animation was done, so I was guaranteed to only have 2 bitmaps loaded at maximum. The Gallery can take up to FIVE Views with the selected, clicked views etc.

I also added this to further isolate memory usage:

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

However, it came with the complication that static classes are not shared across processes. Hence, if in BookActivity I did Engine.SESSION_ID=5 where SESSION_ID is static, I would not be able to read it in BitmapActivity's Engine.SESSION_ID.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文