Подтвердить что ты не робот

Существует ли замена виджета Gallery с View recycling?

Виджет галереи по умолчанию на Android не перерабатывает представления - каждый раз, когда представление для новой позиции называется виджем, всегда вызывает метод getView адаптера с convertView, установленным в null.

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

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

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

4b9b3361

Ответ 1

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

  • AdapterView
  • AbsSpinner

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

После этого я модифицировал код, чтобы сделать следующее:

RecycleBin (AbsSpinner)

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

Gallery

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

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

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

Ответ 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;
}

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