是否存在具有视图回收功能的图库小部件的替代品?

发布于 2024-11-03 03:34:49 字数 341 浏览 5 评论 0原文

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

当您向后和向前滚动时,最终会创建大量视图,而图库存储这些视图的回收器组件似乎无法足够快地回收它们,从而导致 OOM 情况。

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

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

The default Gallery widget on Android does not recycle views - everytime the view for a new position is called the widget always calls the getView method of the adapter with convertView set to null.

As you scroll backwards and forwards this ends up in lots of views being created, which the recycler component that the Gallery stores them in does not seem to recycle them quickly enough leading to an OOM situation.

You can test this easily with a few large-ish images as your gallery items, but just a TextView will cause it in the end. Put a log statement with a counter in the getView method of your adapter also to see how many new views are created.

Does a third-party widget which behaves like a Gallery but that also implements view recycling exist?

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

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

发布评论

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

评论(5

怼怹恏 2024-11-10 03:34:50

参加聚会已经太晚了,但我已经修改了 EcoGallery 来做更多事情(并避免一些崩溃)。

我将其命名为 TimelineGallery,它与 Gallery 相同,但是它可以平滑滚动,并且在异步加载图像时不会做奇怪的事情。

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

原始代码、版权等都属于谷歌,因此责怪他们制造了如此蹩脚的小部件。

最后说明:我不建议使用画廊,它很旧,有缺陷,很糟糕,而且可能永远不会得到维护。问题不在于修复它的错误,问题在于画廊的整个架构是错误的,因此,在不引入更多黑客的情况下修复它是不可能的。

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

如果您仍然想继续使用这个“图库”,请随意,它可以工作,但它可能会使您的应用程序崩溃并使您感到沮丧。

Super late to the party, but I've modified EcoGallery to do a few more things (and avoid some crashes).

I've called it TimelineGallery and it's the same crap as the Gallery, but it can do smooth scroll and doesn't do weird stuff when images are loaded asynchronously.

To demonstrate it, the sample uses Picasso and PullToRefresh.

The original code, copyright and such belongs to Google so blame them for making such a crappy widget.

Final note: I do not recommend using the gallery, it's old, buggy, hacky and will probably never be maintained. The problem is not about fixing its bugs, the problem is that the whole architecture of the Gallery is wrong and as such, fixing it is not possible without introducing more hacks.

Google realized this and deprecated it. Use a ViewPager or a HorizontalScrollList and deal with the limitations of each.

If you still want to go ahead and use this "gallery", feel free, it works, but it may crash your app and may frustrate you.

小帐篷 2024-11-10 03:34:50

针对 OutOfMemory 问题的另一个更快的解决方法是尝试/捕获解码图像的代码,如果抛出 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;
}

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

Another quicker WorkAround for the OutOfMemory Issues, is to try/catch the code where you decode the image and if the OutOfMemory-exception is thrown, you try to decode it with smaller Resolution again..

something like this:

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

Ofcourse it is now possible, that you will see different resolutions of the same picture at different times - But at least your Gallery will not crash anymore and you allways show the highest resolution you can.

墨小墨 2024-11-10 03:34:49

最后,我的解决方案是按照 @CommonsWare 的建议修改 Gallery 源代码。这还需要复制以下文件:

  • AdapterView
  • AbsSpinner

但这些非常简单。

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

RecycleBin (AbsSpinner)

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

图库

  • 使用反射(呃)修改 ViewGroup 的私有 mGroupFlags 变量以允许子级重新排序 - 我还设置了一个布尔值,指示字段访问是否成功我在使用该组件之前进行了测试。
  • 删除了对 mRecycler.clear() 的所有调用
  • 数量
    画廊必须展示的物品
    滚动时会发生变化,并且现有的
    实施将清除
    当 (a) setSelection 为
    称为 (b) 发生运动滚动

通过这些修改,我的适配器中的 newView 方法中的计数器达到了... 7.

此处是代码(于 2013/08/07 置于公共领域 http://en.wikipedia.org/wiki /WTFPL

My solution was, in the end, going with @CommonsWare's suggestion to modify the Gallery source code. This is also required copying the following files:

  • AdapterView
  • AbsSpinner

but these are pretty simple.

After that I modified code to do the following:

RecycleBin (AbsSpinner)

  • Place objects in the recycler one after another, rather than according
    to position
  • Retrieve objects from the bottom of the recycler, regardless of the
    position requested
  • The existing implementation assumed that each different position in the adapter
    resulted in a unique view. The changes above are only good if your Gallery contains
    only one type of item, if not you'll need to add some sort of key based on item type
    and the amount of that type required

Gallery

  • Used reflection (ugh) to modify the private mGroupFlags variable of ViewGroup to allow child re-ordering - I also set a boolean value indicating whether the field access succeeded which I test before using the component.
  • Removed all calls to mRecycler.clear()
  • The number of
    items the gallery has to display
    changes as it scrolls and the existing
    implementation would clear the
    recycler when (a) setSelection was
    called (b) a motion scroll occurred

With these modifications my counter in my newView method in my adapter reached... 7.

Here is the code (Placed in the public domain 2013/08/07 under http://en.wikipedia.org/wiki/WTFPL)

过气美图社 2024-11-10 03:34:49

实际上还有一种替代方案,尽管我还没有亲自测试过:

https://github.com/falnatsheh/EcoGallery< /a>

Actually there is an alternative, though I haven't personally tested it:

https://github.com/falnatsheh/EcoGallery

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