在调用 Honeycomb 活动时清除 Gallery 以避免 OOME?
我正在为 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
啊,那里有相当复杂的代码块。弱引用可能会有所帮助,但一般来说,如果在适配器中使用 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 isdestroy
ed. That should do most of what you need.谢谢!我已经设法重构它以回收位图。但是,图库仍然存在,因为
BitmapActivity.onCreate
在BookActivity.onDestroy
之前被调用。如果我确实调用了 purge() 函数,我将设法清除其中的大部分内容,除了单击/选定的视图(由Gallery
双击侦听器保持活动状态!),然后我清除了该死的画廊并放置我自己的
ImageView imageviewCurrentPage
(和ImageView imageviewFlipperPage
)并对它们进行动画输入和输出。当动画完成时,imageviewFlipperPage 会立即被销毁,所以我保证最多只加载 2 个位图。Gallery
最多可以占用五个 个视图,其中包含选定的、单击的视图等。我还添加了此内容以进一步隔离内存使用情况:
但是,它带来了静态类的复杂性不跨进程共享。因此,如果在 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 beforeBookActivity.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 theGallery
double-tap listener!)I then wiped out the darned gallery and put my own
ImageView imageviewCurrentPage
(and aImageView 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. TheGallery
can take up to FIVE Views with the selected, clicked views etc.I also added this to further isolate memory usage:
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.