14

我正在使用带有 ImageAdapter 的 Gallery 来使用 ImageViews 加载它,从而从我的资源中提取图像。我的问题是,在我的适配器中传递给 getView() 方法的 convertView 始终为空。这意味着每次调用 getView() 时都会创建一个新的 ImageView。这会导致可怕的性能,因为 GC 不断运行以清除所有这些已创建且不再使用的 ImageView。

这显然是一个已知的错误:Gallery 的视图缓存已损坏;从不转换视图。.

我的两个首选解决方案是 1. 在适配器本身中处理视图缓存并处理正确重用它们所需的所有逻辑。或 2. 包含我自己的 Gallery 小部件副本并尝试修复它,以便正确返回回收视图。

我已经开始实施选项一,但很快意识到我并不完全知道如何制作该操作背后的所有逻辑。我开始认为选项二可能更容易。

我在这里找到了 Gallery 小部件的代码:http: //grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.1_r2/android/widget/Gallery.java

我不完全理解它,但我可以看到它正在调用

child = mAdapter.getView(position, null, this);

在第 745 行。我(在黑暗中拍摄)猜测这是问题的根源。

有没有人有这个错误的经验。或者任何人都可以指出我正确的方向来弄清楚回收商的情况是如何工作的,以便我可以调整这个小部件以使其正常工作?甚至建议一些我可能忽略的替代选项。

编辑:我发现的最好的解决方案是一个名为 EcoGallery 的实现。我唯一能在网上找到参考的地方就是这里。为了让它工作,您必须将每个块从那里放在项目中的正确位置。

4

3 回答 3

3

没有特别处理该错误的经验,但我之前使用 3rd 方视图寻呼机(在支持库之前)完成了自定义缓存。

老实说,这真的不是太难。就我而言,我知道屏幕上最多只有一个项目。但我也希望预加载左右的项目(这些是从网络上提取数据的网络视图)。所以我有一个简单的 3 个视图数组。

[V1, V2, V3]

现在您唯一需要做的就是将适配器中的位置与缓存中的位置相关联。有多种方法可以解决这个问题。当我第一次使用它时,我只是将我当前的视图设置为 V2,并在翻转寻呼机时旋转了数组的项目。所以翻转到下一个视图会改变我的数组

[V2, V3, V1]

跟上很简单。或者你可以只做数学计算并计算一个位置到缓存的相对位置。

另一种方法是创建一个后进先出队列。通过将视图推入队列来回收视图,当您需要视图时,只需从中弹出一个即可。

于 2012-06-02T06:11:13.857 回答
1

我没有使用 Gallery 小部件的经验,但我使用了很多带有图像的 ListView。根据你的问题,并链接到谷歌问题,他们仍然没有解决这个问题。

因此,有很好的库(以及其中的示例)的解决方案,可以解决缓存/ajax 问题等等。

链接到图书馆

或者,更具体地说,链接到图像示例

如果您下载他们的示例,您会发现他们如何使用 Gallery 小部件实现画廊,使用他们的 AQuery 实用程序类

com.androidquery.test.image.ImageLoadingGalleryActivity班级。

代码片段:

    final List<Photo> entries;// here only to show what enteries are...

    listAq = new AQuery(this); //define as Action class member, here only to show what it is

    ArrayAdapter<Photo> aa = new ArrayAdapter<Photo>(this, R.layout.gallery_item, entries){

        public View getView(int position, View convertView, ViewGroup parent) {

            if(convertView == null){
                convertView = getLayoutInflater().inflate(R.layout.gallery_item, parent, false);
            }

            Photo photo = getItem(position);

            AQuery aq = listAq.recycle(convertView);

            aq.id(R.id.name).text(photo.title);

            String tbUrl = photo.tb;

            if(!aq.shouldDelay(position, convertView, parent, tbUrl)){
                aq.id(R.id.tb).image(tbUrl);
                aq.id(R.id.text).text(photo.title).gone();
            }else{
                aq.id(R.id.tb).clear();
                aq.id(R.id.text).text(photo.title).visible();
            }


            return convertView;

        }


    };

    aq.id(R.id.gallery).adapter(aa);

其中 Photo 只是 POJO 对象(从远程获取):

class Photo {
    String tb;
    String url;
    String title;
    String author;
}

R.id.gallery

 <Gallery
        android:id="@+id/gallery"
        android:layout_width="fill_parent"
        android:layout_height="200dip" />

R.layout.gallery_item指:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="100dip"
        android:layout_height="75dip" >

        <ProgressBar
            android:id="@+id/progress"
            android:layout_width="15dip"
            android:layout_height="15dip"
            android:layout_centerInParent="true" />

        <ImageView
            android:id="@+id/tb"
            style="@style/GalleryItem"
            android:layout_width="100dip"
            android:layout_height="75dip" />

        <TextView
            android:id="@+id/text"
            android:layout_width="100dip"
            android:layout_height="75dip"
            android:gravity="center"
            android:maxLines="4"
            android:padding="15dip"
            android:text="Dummy TextDummy TextDummy TextDummy TextDummy Text"
            android:textColor="#FFFFFFFF"
            android:textSize="8sp" />

    </RelativeLayout>

希望你会发现这个库对解决你的问题很有用。

于 2012-06-02T17:52:11.380 回答
0

我已经通过使用 dskinner 建议的自定义缓存解决了这个问题。

我预先计算(项目的屏幕宽度/最小宽度)一次可以在屏幕上的画廊中显示的最大项目数并添加更多(画廊将需要额外的项目来显示左右两侧的项目)滚动浏览它)。我创建了一个这种大小的数组 - 视图根据请求创建并放置在缓存中。使用 position % cachesize 来确定调用 getView 时要返回的缓存视图。

于 2012-06-07T11:06:56.233 回答