Gallery ImageAdapter convertView始终为null

时间:2011-10-11 17:14:05

标签: android view widget gallery convertview

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

这显然是一个已知的错误:Gallery's view cache is broken; never converts views.

我的两个首选解决方案是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行。我(在黑暗中拍摄)猜测这是问题的根源。

有没有人有这个bug的经验。或者,任何人都可以指出我正确的方向,以确定回收器的情况如何工作,以便我可以调整这个小部件以正常工作?或者甚至提出一些我可能会忽略的备选方案。

编辑:我找到的最佳解决方案是名为EcoGallery的实施方案。我唯一可以找到它的地方online anymore is here。为了使其正常工作,您必须将每个块放在项目中的正确位置。

3 个答案:

答案 0 :(得分:3)

没有遇到该bug的经验,但我之前使用第三方视图寻呼机(在支持lib之前)进行了自定义缓存。

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

[V1, V2, V3]

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

[V2, V3, V1]

很容易跟上。或者你可以只进行数学运算并计算一个位置到缓存的相对位置。

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

答案 1 :(得分:1)

我没有使用Gallery小部件的经验,但我使用了很多带有图像的ListView。根据您的问题以及Google问题的链接,他们仍然无法解决此问题。

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

链接到library

或更具体地说,链接到图片examples

如果你下载他们的例子,你会发现他们如何使用他们的AQuery实用程序类在

中使用Gallery小部件实现了库。

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>

希望你会发现这个库有助于解决你的问题。

答案 2 :(得分:0)

我已经通过使用自定义缓存来解决这个问题,正如dskinner建议的那样。

我预先计算(项目的屏幕宽度/最小宽度)一次可以在屏幕上显示的项目的最大数量,并添加一些(图库左侧需要额外显示项目和当你滚动它时正确)。我创建了一个这个大小的数组 - 视图按请求创建并放在缓存中。使用position%cachesize来确定调用getView时要返回的缓存视图。