Android: Jank при начальной прокрутке с RecyclerView в отладке - PullRequest
5 голосов
/ 09 июля 2020

У меня есть простое тестовое приложение с макетом, похожим на социальные сети: enter image description here

It consists of an outer recycler view for posts and nested RV for comments (with indentation on the screenshot).

The issue: Mostly in debug mode, there's a considerable jank only when the initial scroll happens (probably some initialization stuff of RVs). Further scrolling is smooth both in debug and release. In release, it happens mostly after usage of some intensive apps, e.g. watching videos on Facebook app. And the jank is less noticeable if it happens in release. Systrace, когда происходит начальная прокрутка

Сведения о настройке

Телефон - Nexus 5X с Android 8.1, compileSdkVersion - 28, minSdkVersion - 16, targetSdkVersion - 28

Соответствующие фрагменты кода следующие:

Внешний адаптер RV - здесь я использую данные сообщений с их комментариями, а также вложенный пул RV, чтобы вложенные RV могли воспользоваться этим. Держатель представления просто хранит некоторые ссылки на различные элементы управления в представлении. onCreateViewHolder - это место, где я пробовал некоторые оптимизации, включая предварительное создание 10 держателей представлений (текущий код). Я установил для setHasFixedSize значение true, но это не помогло. Менеджер компоновки для RV: LinearLayoutManager без какой-либо настройки.

if (viewHolders.size == 0) {
        //Log.w("msg", "creating all view holders")
        for (i in 1..10) {
            val v = LayoutInflater.from(parent.context)
                    .inflate(R.layout.wallpost_view, parent, false) as LinearLayout
            val viewHolder = MyViewHolder(v, context, nestedViewsPool)
            viewHolders.push(viewHolder)
        }
    }

Внутренний адаптер RV - здесь ничего особенного, поскольку он в настоящее время не содержит никаких настраиваемых события.

Внешний вид элемента RV - Да, он использует вложенные макеты , но я не заметил никакой разницы в производительности при включении его в ConstraintLayout, Версия CL здесь .

Вид внутреннего RV элемента - Здесь ничего особенного, похоже на внешний вид элемента, но без кнопок и ссылок. версия CL здесь

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

Ответы [ 2 ]

3 голосов
/ 17 июля 2020

Несколько вещей, о которых нужно позаботиться

1 - не измерять производительность в режиме отладки

Я не могу этого особо подчеркнуть. Запустите без подключенного отладчика, и вы увидите drasti c повышение производительности.

2- сгладьте свой дизайн

Вместо RV, где каждый элемент имеет RV, используйте один RecyclerView с разными ячейками . Таким образом, 1-я ячейка будет «содержимым настенного поста», 2-я будет «ответом на настенный пост 1», 3-я «настенным ответом 2» и т. Д. c.

Я изо всех сил пытался заставить один из моих экранов работать лучше, когда у нас есть горизонтальный RV (viewPager 2 должен быть указан c) с вложенным вертикальным RV, и я преследовал множество тупиков, и в итоге пришлось использовать некоторые трюки, такие как отключение предварительной загрузки предыдущей / следующей страницы, пока текущая страница не будет загружен. Но он НЕ работает после начальной загрузки.

3- Наличие <include в макетах вряд ли замедлит его.

Но наличие вложенных иерархий делает, например:

<LinearLayout> 
  <LinearLayout>
    <LinearLayout>

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

и последний

4- будьте осторожны с преобразованием даты

Я заметил, что там - это некоторые методы в ThreeTenAbp, которые отнимают неоправданно много времени. Попробуйте пропустить все эти методы, заменив их фиктивными строками, и проверьте, имеет ли это значение. Если это так, у вас есть несколько вариантов, но это 2 моих первоначальных подозреваемых

  • инициализировать форматеры даты только один раз и использовать их в фоновом потоке
  • проверьте, что ваши парсеры даты работает в фоновом потоке

Я не удивлюсь, если Java 8 DateTime будет иметь те же проблемы.

============= ===

Написав все вышесказанное, я взглянул на вашу систрасу. На первый взгляд кажется, что виноваты вложенные линейные схемы. Около 1,880 мс я вижу, что очень долгое надувание занимает 30 мс, это большой красный флаг. У него есть 3 линейных макета внутри, которые будут иметь тенденцию указывать в общем направлении либо внутреннего, либо внешнего макета. Поэтому я сначала попробую (3), а если недостаточно, то попробую (2).

============== Изменить: добавление (5 )

5- совместное использование RecycledViewPool для внутреннего recyclerview

Создайте единственный объект типа RecycledViewPool и назначьте его всем вашим внутренним recyclerviews. https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.RecycledViewPool

1 голос
/ 12 июля 2020

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

Я переместил предварительное создание двух типов держателей представлений в вызывающую активность:

for (i in 1..30) {
    val v = LayoutInflater.from(parent.context).inflate(R.layout.wallpost_view, parent, false) as LinearLayout
    val viewHolder = MyViewHolder(v, context, nestedViewsPool)
    viewHolders.push(viewHolder)
}

for (i in 1..20) {
    val v = LayoutInflater.from(this).inflate(R.layout.comment_view, null) as LinearLayout
    val viewHolder = WallpostsListAdapter.CommentsViewHolder(v)
    adapter.commentViewHolders.push(viewHolder)
}

Это сделало первую прокрутку в 2 раза быстрее в большинстве проведенных мною тестов. И это действие привело к наибольшему выигрышу в процессе оптимизации.

Я также принял часть предложений @ Fabio :

1. Как я уже говорил в комментариях, я измеряю эти данные в режиме отладки, чтобы лучше видеть результаты оптимизации. В выпуске, конечно, числа в миллисекундах будут намного меньше (на самом деле примерно в 10 раз меньше, чем я видел в системе в выпуске).

2. дала самую большую разницу, небольшую разницу, но все же ее можно было заметить в systrace. Для получения дополнительной информации проверьте pastebins в конце ответа.

3. Действительно, Google рекомендует использовать ContraintLayout вместо вложенных макетов, но в моем случае это не имело никакого значения . На самом деле вложенные линейные макеты, похоже, показали немного лучшие результаты. Я предполагаю, что виды недостаточно сложны, чтобы увидеть выигрыш с CL. Я не смог протестировать окончательный оптимизированный код с вложенными линейными макетами, потому что теперь я использую один многовидовой вид RV, и они не работали с ним правильно, не могли найти причину, но, вероятно, выигрыша не было бы это значимо.

4. Хороший аргумент, но, по крайней мере, в моем случае это не имело никакого значения.

5. Устарело, так как теперь есть только один жилой дом без вложенности.

Соответствующий код

  • Адаптер для дома на колесах - теперь вид для разных типов адаптер, управляющий как сообщениями, так и комментариями. Самым большим изменением было то, что мне нужно было написать код сопоставления между позицией RV и индексом массива. Теперь при инициализации мне нужно сделать это сопоставление. В привязке VH комментария мне сначала нужно получить позицию RV их родительского поста, оттуда индекс в массиве и, наконец, из их разницы, чтобы получить индекс комментария в массиве комментариев поста.
  • Представление поста с ConstraintLayout
  • Представление комментария с CL

Systraces

  • Представления с CL, все просмотр предварительно созданных держателей, одиночный RV - здесь
  • Просмотры с CL, только предварительно созданный VH поста, одиночный RV - здесь
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...