Существует ли замена виджета Gallery с View recycling?
Виджет галереи по умолчанию на Android не перерабатывает представления - каждый раз, когда представление для новой позиции называется виджем, всегда вызывает метод getView
адаптера с convertView
, установленным в null.
Когда вы прокручиваете назад и вперед, это заканчивается множеством создаваемых представлений, которые, как представляется, перерабатывают компоненты, хранящиеся в них в галерее, не слишком быстро перерабатывают их, что приводит к ситуации OOM.
Вы можете легко протестировать это с помощью нескольких изображений с большим количеством изображений в качестве элементов вашей галереи, но только TextView вызовет это в конце. Поместите оператор журнала с помощью счетчика в метод getView
вашего адаптера, чтобы узнать, сколько новых представлений создано.
Существует ли сторонний виджет, который ведет себя как Галерея, но также реализует переработку вида?
Ответы
Ответ 1
Мое решение было, в конце концов, с предложением @CommonsWare изменить исходный код Gallery. Это также требуется для копирования следующих файлов:
но это довольно просто.
После этого я модифицировал код, чтобы сделать следующее:
RecycleBin
(AbsSpinner
)
- Поместите объекты в ресайклеров один за другим, а не в соответствии с на позицию
- Извлечь объекты из нижней части ресайклера, независимо от запрошенная позиция
- В существующей реализации предполагается, что каждое другое положение в адаптере привели к уникальному виду. Изменения, внесенные выше, хороши только в том случае, если ваша Галерея содержит только один тип элемента, если нет, вам нужно будет добавить какой-то ключ по типу элемента и требуется количество этого типа
Gallery
- Использовать отражение (ugh) для изменения частной переменной
mGroupFlags
ViewGroup
, чтобы разрешить переупорядочивание ребёнка. Я также устанавливаю логическое значение, указывающее, удалось ли получить доступ к полю, который я тестирую перед использованием компонента. - Удалены все вызовы
mRecycler.clear()
- Число элементы, которые должна отображать галерея изменяется по мере прокрутки и существующих осуществление будет recycler, когда (a) setSelection был (b) произошла прокрутка движения.
С этими изменениями мой счетчик в моем методе newView
в моем адаптере достиг... 7.
Вот код (размещен в общественном достоянии 2013/08/07 под http://en.wikipedia.org/wiki/WTFPL)
Ответ 2
На самом деле есть альтернатива, хотя я лично ее не тестировал:
https://github.com/falnatsheh/EcoGallery
Ответ 3
Я использовал патч из http://code.google.com/p/android/issues/detail?id=3376#c19
Ответ 4
Супер опоздал на вечеринку, но я изменил EcoGallery, чтобы сделать еще несколько вещей (и избежать некоторых сбоев).
Я назвал его TimelineGallery и это тот же дерьмо, что и Галерея, но он может сделать гладкая прокрутка и не делает странных вещей, когда изображения загружаются асинхронно.
Чтобы продемонстрировать это, образец использует Picasso и PullToRefresh.
Оригинальный код, авторское право и т.д. принадлежат Google, поэтому обвиняйте их в создании такого дерьмового виджета.
Заключительное примечание: я не рекомендую использовать галерею, она старая, багги, хаки и, вероятно, никогда не будет поддерживаться. Проблема не в исправлении ошибок, проблема в том, что вся архитектура Галереи ошибочна, и поэтому ее исправление невозможно без введения дополнительных хаков.
Google осознал это и отказался от этого. Используйте ViewPager или HorizontalScrollList и используйте ограничения каждого из них.
Если вы все еще хотите пойти и использовать эту "галерею", не стесняйтесь, она работает, но может привести к сбою вашего приложения и может вас разочаровать.
Ответ 5
Еще один быстрый WorkAround для проблем OutOfMemory - это попробовать/уловить код, в котором вы декодируете изображение, и если выбрано исключение OutOfMemory, вы пытаетесь его декодировать с меньшим разрешением снова.
что-то вроде этого:
private static Bitmap decodeFile(File f, int size, int suggestedScale) {
int scale = 1;
Bitmap bmp = null;
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
if(suggestedScale > 0)
scale = suggestedScale;
else {
if (width_tmp >= height_tmp) {
scale = Math.round((float)(width_tmp) / size);
} else {
scale = Math.round((float)(height_tmp) / size);
}
}
if(scale < 2)
return BitmapFactory.decodeFile(f.getPath());
Debug.i(TAG, "width: " + width_tmp + " height: " + height_tmp + " scale: " + scale);
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
} catch(OutOfMemoryError e) {
Debug.i(TAG, "we retry it cause of an OutOfMemoryException");
return decodeFile(f, size, scale+1);
} catch(Exception e){
Debug.w(TAG, e);
}
return bmp;
}
Конечно, теперь возможно, что вы будете видеть разные разрешения одной и той же картины в разное время. Но по крайней мере ваша галерея больше не будет разбиваться, и вы всегда показываете самое высокое разрешение, которое вы можете.