Android上的默认Gallery小部件不会回收视图 - 每次调用新位置的视图时,小部件总是调用适配器的getView
方法,convertView
设置为null。
当你向前和向后滚动时,这会在创建的大量视图中结束,Gallery所存储的回收器组件似乎不会足够快地回收它们导致OOM情况。
您可以使用一些大图像作为您的图库项目轻松测试,但只有TextView最终会导致它。在适配器的getView
方法中放置带有计数器的日志语句,以查看创建了多少新视图。
是否存在行为类似于Gallery但又实现了视图回收的第三方窗口小部件?
答案 0 :(得分:24)
我的解决方案最终是以@CommonsWare的建议来修改Gallery源代码。这也需要复制以下文件:
AdapterView
AbsSpinner
但这些很简单。
之后我修改了代码以执行以下操作:
RecycleBin
(AbsSpinner
)
- 将物品一个接一个地放在回收器中,而不是按照 定位
- 从回收站底部检索对象,无论其如何 请求的位置
- 现有实现假定适配器中的每个不同位置 产生了独特的观点。如果您的图库包含,则上述更改仅适用 只有一种类型的项目,如果不是,你需要根据项目类型添加某种键 以及所需类型的数量
Gallery
- 使用反射(ugh)修改
mGroupFlags
的私有ViewGroup
变量以允许子重新排序 - 我还设置了一个布尔值,指示在使用组件之前我测试的字段访问是否成功- 删除了对
的所有来电mRecycler.clear()
- 数量 图库必须显示的项目 滚动和现有的变化 实施将清除 回收者在(a)setSelection时 叫(b)发生动画滚动
通过这些修改,我的适配器newView
方法中的计数器达到了...... 7。
Here is the code(置于http://en.wikipedia.org/wiki/WTFPL下的公共领域2013/08/07)
答案 1 :(得分:1)
实际上有一种替代方案,但我没有亲自测试过它:
答案 2 :(得分:0)
答案 3 :(得分:0)
派对超级晚了,但我已经修改了EcoGallery来做更多的事情(避免一些崩溃)。
我称之为TimelineGallery并且它与相同的废话与画廊,但它可以做平滑滚动,并且在异步加载图像时不会做奇怪的事情。
为了演示它,该示例使用Picasso和PullToRefresh。
原始代码,版权等属于Google,因此责怪他们制作如此糟糕的小部件。
最后说明:我不建议使用画廊,它是旧的,越野车,hacky,可能永远不会被维护。问题不在于修复它的错误,问题在于Gallery的整个架构是错误的,因此,如果不引入更多的黑客攻击,就不可能修复它。
谷歌意识到这一点并弃用了它。使用ViewPager或HorizontalScrollList并处理每个限制。如果您仍想继续使用此“图库”,请随意使用,但它可能会使您的应用崩溃并可能会让您感到沮丧。
答案 4 :(得分:-1)
OutOfMemory问题的另一个更快的WorkAround是尝试/捕获解码图像的代码,如果抛出OutOfMemory异常,则尝试再次使用较小的分辨率对其进行解码。
类似的东西:
private static Bitmap decodeFile(File f, int size, int suggestedScale) {
int scale = 1;
Bitmap bmp = null;
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
if(suggestedScale > 0)
scale = suggestedScale;
else {
if (width_tmp >= height_tmp) {
scale = Math.round((float)(width_tmp) / size);
} else {
scale = Math.round((float)(height_tmp) / size);
}
}
if(scale < 2)
return BitmapFactory.decodeFile(f.getPath());
Debug.i(TAG, "width: " + width_tmp + " height: " + height_tmp + " scale: " + scale);
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
} catch(OutOfMemoryError e) {
Debug.i(TAG, "we retry it cause of an OutOfMemoryException");
return decodeFile(f, size, scale+1);
} catch(Exception e){
Debug.w(TAG, e);
}
return bmp;
}
当然现在有可能,你会在不同的时间看到同一张图片的不同分辨率 - 但至少你的画廊不会再崩溃,你总是可以显示最高的分辨率。