Галерея ImageAdapter convertView всегда пуста
Я использую Галерея с ImageAdapter, чтобы загрузить его с ImageViews, которые извлекают изображения из моих ресурсов. Моя проблема в том, что convertView, который передается методу getView() в моем адаптере, всегда имеет значение null. Это означает, что новый ImageView создается каждый раз, когда вызывается getView(). Это приводит к ужасному предварительному исполнению, потому что GC постоянно работает, чтобы стереть все эти созданные и более не используемые ImageView.
Это, по-видимому, известная ошибка: кеш представления галереи не работает; никогда не конвертирует взгляды.,
Мои два предпочтительных решения: 1. Обрабатывать кэш представлений в самом адаптере и позаботиться о всей логике, необходимой для их повторного использования. или 2. включить мою собственную копию виджета "Галерея" и попытаться исправить ее, чтобы она правильно возвращала переработанные виды.
Я начал реализацию первого варианта, но быстро понял, что точно не знаю, как реализовать всю логику этой операции. Я начинаю думать, что второй вариант может быть проще.
Я нашел код для виджета Галерея здесь: 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. Единственное место, где я могу найти ссылку на это онлайн, это здесь. Чтобы это работало, вы должны поместить каждый кусок в нужное место в вашем проекте.
3 ответа
В частности, я не сталкивался с этой ошибкой, но раньше я делал пользовательское кэширование с помощью стороннего пейджера (до поддержки lib).
Честно говоря, это не так уж сложно. В моем случае я знал, что на экране будет максимум один элемент. Но я также хотел, чтобы элемент слева и справа был предварительно загружен (это были веб-просмотры, извлекающие данные из сети). Итак, у меня есть простой массив из 3 представлений.
[V1, V2, V3]
Теперь единственное, что вам нужно сделать, это соотнести позицию в вашем адаптере с позицией в вашем кэше. Есть множество способов справиться с этим. Когда я впервые сделал это, я просто сделал то, что было моим текущим представлением, чтобы быть V2, и поворачивал элементы массива вокруг, переворачивая пейджер. Так что переход к следующему представлению изменит мой массив
[V2, V3, V1]
Было просто не отставать. Или вы можете просто сделать математику и вычислить позицию относительно позиции кэша.
Другой подход заключается в создании очереди "первым пришел - первым вышел". Перерабатывайте представления, помещая их в очередь, и, когда вам нужно представление, просто извлеките одно из них.
У меня нет опыта работы с виджетом Галерея, но я часто использую ListView с изображениями. В соответствии с вашей проблемой и ссылкой на проблему Google, они до сих пор не решили эту проблему.
Итак, есть решение с хорошей библиотекой (и примерами внутри нее), которая решает проблемы с кешем /ajax и многое другое.
Ссылка на библиотеку
или, более конкретно, ссылку на примеры изображений
Если вы скачаете их примеры, вы увидите, как они реализовали галерею с помощью виджета Галерея, используя свой служебный класс 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>
Надеюсь, вы найдете эту библиотеку полезной для решения вашей проблемы.
Я справился с этим, используя собственный кеш, как подсказывает dskinner.
Я предварительно вычисляю (ширина экрана / минимальная ширина элемента) максимальное количество элементов, которые можно показать в галерее на экране за один раз, и добавляю еще несколько (галерее понадобятся дополнительные элементы для отображения элементов слева и справа по мере того, как вы прокрутите через него). Я создаю массив такого размера - представления создаются по запросу и помещаются в кеш. Используйте position % cachesize, чтобы выяснить, какое кэшированное представление будет возвращено при вызове getView.