图库ImageAdapter中的convertView始终为null

14
我正在使用一个带有ImageAdapter的Gallery来加载从资源中获取的ImageView,但是我的问题是在我的适配器中传递给getView()方法的convertView始终为空。这意味着每次调用getView()都会创建一个新的ImageView。由于GC不断运行以清除所有已创建但不再使用的ImageView,这导致性能非常糟糕。
这显然是一个已知的bug: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的实现。唯一能够找到它的地方在线上。要使其工作,您必须将其中每个块放置在项目的正确位置。


可能会有所帮助 https://dev59.com/VWTWa4cB1Zd3GeqPB0pW - Mehul
3个回答

3

我没有特别接触过这个bug,但我曾经在使用第三方视图页(在使用支持库之前)时进行过自定义缓存。

说实话,这并不太难。在我的情况下,我知道屏幕上最多只有一个项目。但我也想要左右的项目被预加载(这些是从网络上获取数据的Web视图)。所以我有一个简单的3个视图的数组。

[V1, V2, V3]

现在您需要做的唯一一件事就是将适配器中的位置与缓存中的位置相关联。有很多方法可以解决这个问题。当我第一次尝试时,我只是将当前视图设为V2,并在翻转页面时旋转数组中的项目。因此,翻到下一个视图将改变我的数组。
[V2, V3, V1]

很容易跟进。或者你可以进行计算,将位置转换为缓存的相对位置。

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


我曾尝试使用队列对象来保存我的视图,但一直没有成功。不过我同意这种方法是可行的 =) - FoamyGuy
使用一个视图数组来缓存你的视图,然后 cachePos = position % VIEW_CACHE_SIZE - shaobin0604

1

我没有使用过Gallery小部件,但是我经常使用带有图像的ListView。根据您的问题和Google问题链接,他们仍然没有解决这个问题。

因此,有一个很好的库(其中包含示例),可以解决缓存/ ajax问题等等。

链接到library

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

如果您下载他们的示例,您将发现他们如何使用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>

希望您能在解决问题时发现这个库很有用。

0
我已经按照dskinner的建议使用自定义缓存解决了这个问题。
我预先计算了画廊中屏幕同时可以显示的最大项目数量(item的最小宽度/screenwidth),并添加了一些额外的项目(当您滚动时,画廊需要额外的项目来显示左侧和右侧的项)。 我创建了一个此大小的数组-视图在请求时创建并放置在缓存中。 使用position%cachesize来确定调用getView时返回哪个缓存视图。

一个小的代码示例或者一些代码/代码片段的链接在这里会非常有帮助。 - iwein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接