Существует ли замена для виджета Галерея с утилизацией View?

Стандартный виджет "Галерея" на Android не изменяет представления - каждый раз, когда вызывается представление для новой позиции, виджет всегда вызывает getView метод адаптера с convertView установить на ноль.

Когда вы прокручиваете назад и вперед, это приводит к тому, что создается много представлений, которые, по-видимому, перерабатывает компонент рециркуляции, в котором их хранит Галерея, и приводит к ситуации с OOM.

Вы можете легко проверить это с помощью нескольких изображений большого размера в качестве элементов галереи, но только TextView вызовет это в конце. Поместите запись журнала со счетчиком в getView Метод вашего адаптера также, чтобы увидеть, сколько новых видов создаются.

Существует ли сторонний виджет, который ведет себя как галерея, но также реализует переработку вида?

5 ответов

Решение

В конце концов, мое решение заключалось в предложении @CommonsWare изменить исходный код галереи. Для этого также необходимо скопировать следующие файлы:

  • AdapterView
  • AbsSpinner

но это довольно просто.

После этого я изменил код, сделав следующее:

RecycleBin (AbsSpinner)

  • Размещайте предметы в утилизаторе один за другим, а не в соответствии с положением
  • Извлекать предметы из нижней части рециркулятора, независимо от запрошенной позиции
  • Существующая реализация предполагала, что каждая отдельная позиция в адаптере приводила к уникальному представлению. Вышеуказанные изменения хороши только в том случае, если ваша Галерея содержит только один тип элемента, в противном случае вам нужно будет добавить какой-то ключ на основе типа элемента и требуемого количества этого типа.

Gallery

  • Используется отражение (тьфу), чтобы изменить приват mGroupFlags переменная ViewGroup чтобы разрешить повторное упорядочение дочерних элементов - я также установил логическое значение, указывающее, успешно ли получен доступ к полю, который я тестировал перед использованием компонента.
  • Убраны все звонки на mRecycler.clear()
  • Число элементов, которые галерея должна отображать, изменяет при прокрутке, и существующая реализация очищает утилиту при вызове (a) setSelection (b) произошла прокрутка движения

С этими модификациями мой счетчик у меня newView метод в моем адаптере достиг... 7.

Вот код (размещен в открытом доступе 2013/08/07 под http://en.wikipedia.org/wiki/WTFPL)

На самом деле есть альтернатива, хотя я лично не проверял ее:

https://github.com/falnatsheh/EcoGallery

Очень поздно для вечеринки, но я изменил EcoGallery, чтобы сделать еще несколько вещей (и избежать некоторых сбоев).

Я назвал это TimelineGallery, и это то же самое дерьмо, что и Gallery, но он может выполнять плавную прокрутку и не делает странных вещей, когда изображения загружаются асинхронно.

Чтобы продемонстрировать это, в примере используются Picasso и PullToRefresh.

Оригинальный код, авторские права и тому подобное принадлежит Google, поэтому вините их за создание такого дерьмового виджета.

Последнее замечание: я не рекомендую использовать галерею, она старая, глючная, взломанная и, вероятно, никогда не будет поддерживаться. Проблема не в том, чтобы исправить ошибки, а в том, что вся архитектура Галереи неверна и, как таковая, исправить ее невозможно без введения дополнительных хаков.

Google понял это и осудил это. Используйте ViewPager или HorizontalScrollList и разберитесь с ограничениями каждого из них.

Если вы все еще хотите пойти дальше и использовать эту "галерею", не стесняйтесь, она работает, но она может привести к сбою вашего приложения и может вас расстроить.

Я использовал патч от http://code.google.com/p/android/issues/detail?id=3376

Еще один более быстрый способ обойти проблемы 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;
}

Конечно, теперь возможно, что вы увидите разные разрешения одного и того же изображения в разное время - но, по крайней мере, ваша Галерея больше не будет падать, и вы всегда будете показывать самое высокое разрешение, какое только сможете.

Другие вопросы по тегам