是否存在使用View回收的Gallery小部件替换?

时间:2011-04-26 11:52:29

标签: android view gallery out-of-memory recycle

Android上的默认Gallery小部件不会回收视图 - 每次调用新位置的视图时,小部件总是调用适配器的getView方法,convertView设置为null。

当你向前和向后滚动时,这会在创建的大量视图中结束,Gallery所存储的回收器组件似乎不会足够快地回收它们导致OOM情况。

您可以使用一些大图像作为您的图库项目轻松测试,但只有TextView最终会导致它。在适配器的getView方法中放置带有计数器的日志语句,以查看创建了多少新视图。

是否存在行为类似于Gallery但又实现了视图回收的第三方窗口小部件?

5 个答案:

答案 0 :(得分:24)

我的解决方案最终是以@CommonsWare的建议来修改Gallery源代码。这也需要复制以下文件:

  • AdapterView
  • AbsSpinner

但这些很简单。

之后我修改了代码以执行以下操作:

  

RecycleBinAbsSpinner

     
      
  • 将物品一个接一个地放在回收器中,而不是按照   定位
  •   
  • 从回收站底部检索对象,无论其如何   请求的位置
  •   
  • 现有实现假定适配器中的每个不同位置   产生了独特的观点。如果您的图库包含,则上述更改仅适用   只有一种类型的项目,如果不是,你需要根据项目类型添加某种键   以及所需类型的数量
  •   
     

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)

实际上有一种替代方案,但我没有亲自测试过它:

https://github.com/falnatsheh/EcoGallery

答案 2 :(得分:0)

答案 3 :(得分:0)

派对超级晚了,但我已经修改了EcoGallery来做更多的事情(避免一些崩溃)。

我称之为TimelineGallery并且它与相同的废话与画廊,但它可以做平滑滚动,并且在异步加载图像时不会做奇怪的事情。

为了演示它,该示例使用Picasso和PullToRefresh。

原始代码,版权等属于Google,因此责怪他们制作如此糟糕的小部件。

最后说明:我不建议使用画廊,它是旧的,越野车,hacky,可能永远不会被维护。问题不在于修复它的错误,问题在于Gallery的整个架构是错误的,因此,如果不引入更多的黑客攻击,就不可能修复它。

谷歌意识到这一点并弃用了它。使用ViewPager或Horizo​​ntalScrollList并处理每个限制。

如果您仍想继续使用此“图库”,请随意使用,但它可能会使您的应用崩溃并可能会让您感到沮丧。

答案 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;
}

当然现在有可能,你会在不同的时间看到同一张图片的不同分辨率 - 但至少你的画廊不会再崩溃,你总是可以显示最高的分辨率。