我正在使用带有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。为了使其正常工作,您必须将每个块放在项目中的正确位置。
答案 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时要返回的缓存视图。