Recyclerview onCreateViewHolder вызывается несмотря на то, что все представления перерабатываются?

Короткая история: у меня есть (предварительное кэширование) Custom LinearLayoutManager, RecyclerView, Custom RecyclerView.Adaptor, Custom RecyclerView.ViewHolder настроить. У меня есть только один viewType и облегченные функции привязки. Это действительно ничего особенного, поэтому я надеюсь, что мне не нужно размещать код. Я также не хочу путать со всем несоответствующим кодом.

Проблема, с которой я столкнулся, заключается в том, что, несмотря на то, что не удается перезапустить какие-либо представления, onCreateViewHolder по-прежнему вызывается время от времени (после начального надувания строк), что заставляет меня задуматься о возможной утечке памяти? Как вы думаете, это так и почему? Что решает, что моему приложению по-прежнему нужно создавать больше представлений, а не перерабатывать?

Я добавлю одну вещь, которая может быть как-то с учетом. Мои строки имеют два визуальных состояния (они расширяются и сворачиваются), и кажется, что наличие более случайного сочетания строк в разных состояниях усугубляет проблему.

Полная история: я заметил случайный сбой в плавной прокрутке моего RecyclerView, Используя профилировщик android studio, я заметил следующее:

  1. Все мое bindViewHolder методы очень быстрые и не сдерживают прокрутку.
  2. OnCreateViewHolder это то, что вызывает заикание. Это объясняет, почему во время первой прокрутки всегда есть несколько заиканий. Кроме того, это инфляция, которая занимает смехотворно высокий процент времени процессора.
  3. С макетом элемента / строки, построенным с использованием ConstraintLayout, onMeasure плохая производительность функций, разрушил производительность прокрутки на более слабых устройствах.
  4. С макетом элемента / строки, построенным с использованием LinearLayoutс, производительность резко улучшилась. Тем не менее, инфляция мнений все еще занимает достаточно много времени, чтобы вызвать взлеты.

Имея эту информацию, я максимально упростил макет элемента строки, убедившись, что он используется LinearLayouts. Несмотря на это, рендеринг элементов в окне повторного просмотра не должен приводить к заиканию после появления первых элементов на экране, поскольку, во-первых, все строки одинаковы, за исключением данных, связанных с ними, и двух, RecyclerView должен перерабатывать строки. Так onCreateViewHolder сначала нужно вызвать много, а потом снова редко. Как насчет предварительного кэширования? Я обнаружил, что это одна из причин, по которой при прокрутке запрашиваются новые пользователи. Я установил кеш и создал кастом LinearLayoutManager который переопределяет метод предварительного кэширования (pre-fetching?), называемый getExtraLayoutSpace(RecyclerView.State state) и скорректировал их так, чтобы было достаточно существующих перерабатываемых видов для покрытия запроса во время прокрутки. Мои тесты подтверждают, что после начальной прокрутки новые виды не запрашиваются при переходе в состояние прокрутки.

Все это и у меня осталось две проблемы. Одним из них является то, что onCreateViewHolder вызывается очень часто во время использования приложения, и это вызывает небольшой сбой. Я положил Log.w() внутри onFailedToRecycleView() чтобы увидеть, что любые виды не перерабатываются, и похоже, что виды перерабатываются. Так что теперь я думаю, что есть некоторая утечка памяти, и профилировщик памяти показывает скачки в использовании памяти, часто происходящие, когда onCreateViewHolder называется.

1 ответ

Два вопроса, которые я разместил где,

  1. У меня утечка памяти, потому что Recyclerview продолжает создавать виджеты?
  2. Почему у меня утечка памяти?
  3. Что решает, что моему приложению по-прежнему нужно создавать больше представлений, а не перерабатывать?

Я считаю, что по сути я нашел решение 2 из 3 вопросов или соответствующих основных проблем.

внутри Recyclerview класс Recycler класс и RecycledViewPool учебный класс. внутренний Recycler объект это то, что делает запрос к RecycledViewPool объект для доступного отдельного держателя скрапа для переработки, если у него еще нет прикрепленного держателя скрапа для переработки. И, в частности, этот поиск перерабатываемого держателя просмотра происходит внутри Recycler "s getViewForPosition(int position) функция. Если (внутри этой функции) перерабатываемый вид не найден, то mAdapter.createViewHolder(RecyclerView.this, type) называется. Это ведет к onCreateViewholder будучи призванным Таким образом, чтобы ответить на 3-й вопрос, Recycler решает, когда вызывать onCreateViewholder.

Обратите внимание, что RecycledViewPool Задача состоит в том, чтобы поддерживать массив списков массивов отдельных просмотренных элементов записок (массив 1d массивов каждого viewType). Поддерживающие функции включают clear(), reset(), а также setMaxScrap(int viewType, int max) которые делают то, что указывают их имена. Таким образом, путь к решению второго вопроса заключается в создании пользовательского RecycledViewPool, который указывает, когда скраплист очищается или уменьшается, чтобы я мог отслеживать создание и уничтожение представлений скрапа. Что касается вопроса 1, это можно решить с помощью setMaxScrap(int viewType, int max), Кроме того, при инициализации просмотра повторного просмотра мы можем поместить несколько дополнительных просмотров в пул и попытаться сохранить минимальное количество просмотров, которое, вероятно, можно выполнить с помощью прослушивателя.

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