Recyclerview может быть настолько гладким, что нельзя пропустить эти 14 стратегий оптимизации...
Recyclerview может быть настолько гладким, что нельзя пропустить эти 14 стратегий оптимизации...

введение

В разработке для Android RecyclerView — это часто используемый элемент управления списком, используемый для отображения больших объемов данных. Однако по мере увеличения объема данных производительность RecyclerView может снизиться, что приведет к таким проблемам, как задержки и утечки памяти. В этой статье будут представлены некоторые методы оптимизации, которые помогут вам повысить производительность RecyclerView, чтобы она оставалась бесперебойной при различных обстоятельствах.

Идеи по оптимизации

Основные идеи оптимизации производительности RecyclerView можно свести к следующим аспектам:

  1. Оптимизация макета: оптимизация RecyclerView измакетструктура,Уменьшить уровень вложенности,Повышение эффективности макета.
  2. Уменьшить рисунок: максимально уменьшите количество прорисовок вида, чтобы избежать потребления изпроизводительности, вызванного перерисовкой.
  3. Скользящая оптимизация: существовать Во время скольжения,Максимально сократить трудоемкие операции,Избегайте влияния на эффект скольжения.
  4. предварительная загрузка: предварительная загрузка скоро будет из просмотра,Улучшение отображенияпроизводительность。
  5. Оптимизация памяти: Уменьшите потребление памяти.,Разумно освободить память,Избегайте утечек памяти.

Ниже приведены конкретные стратегии оптимизации для каждого из них.

Оптимизация макета

  1. Уменьшите вложенность макетов

Избегайте использования слишком большого количества вложенных макетов и сложных иерархий в макете элемента RecyclerView, что увеличит время и потребление ресурсов рендеринга. Попробуйте использовать простую структуру макета и рационально использовать эффективные макеты, такие как ConstraintLayout.

Язык кода:javascript
копировать
<!-- item_layout.xml -->
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <!-- Другие компоненты представления -->

</androidx.constraintlayout.widget.ConstraintLayout>
  1. Используйте тег слияния для объединения макета

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

Язык кода:javascript
копировать
<!-- Используйте тег слияния для объединения макета -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/image" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Text" />
</merge>
  1. Включить setHasFixedSize

настраивать setHasFixedSize(true) назад,RecyclerView предполагает, что высота всех элементов фиксирована.,Перерасчет не произойдет из-за изменений в Itemiz,избегатьrequestLayoutпривести киз Пустая трата ресурсов。

Язык кода:javascript
копировать
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
recyclerView.setHasFixedSize(true)

Следует отметить, что использование setHasFixedSize(true)Применяется ко всемItemВысота фиксирована и не меняется.из Состояние。еслиItemВысота не фиксирована или может меняться.,Этот метод следует избегать,В противном случае макет может отображаться ненормально.

Уменьшить рисунок

  1. Использование DiffUtil для обновления данных

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

Язык кода:javascript
копировать
class MyDiffCallback(private val oldList: List<String>, private val newList: List<String>) : DiffUtil.Callback() {
    override fun getOldListSize(): Int {
        return oldList.size
    }

    override fun getNewListSize(): Int {
        return newList.size
    }

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition] == newList[newItemPosition]
    }

    override fun areContentsTheSame(oldItemPosition: Int,newItemPosition: Int): Boolean {
        return oldList[oldItemPosition] == newList[newItemPosition]
    }
}

// существоватьAdapterПрименение вDiffUtil
val diffResult = DiffUtil.calculateDiff(MyDiffCallback(oldList, newList))
diffResult.dispatchUpdatesTo(this)
  1. Ограничьте количество элементов списка

Если объем данных в списке очень велик, вы можете рассмотреть возможность загрузки страниц или загрузки данных только в пределах видимого диапазона, чтобы уменьшить использование памяти и время рендеринга.

Язык кода:javascript
копировать
// Загружать только видимый диапазон изданных
recyclerView.layoutManager?.setInitialPrefetchItemCount(10)

Скользящая оптимизация

  1. существоватьonCreateViewHolderсередина Выполните необходимые операции инициализации

существуютViewHolderиз Этап создания,Выполните необходимые операции инициализации,Такие как настройки монитора и т.д.,избегатьсуществоватьonBindViewHolder()середина进行耗时操作,Улучшение прокруткипроизводительность。

Язык кода:javascript
копировать
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
    val viewHolder = ViewHolder(view)
    // Выполните необходимые операции инициализации
    return viewHolder
}
  1. Сдвиньте, чтобы остановить операцию загрузки

может пройти RecyclerView.addOnScrollListener(listener) Метод добавляет прослушиватель прокрутки, а затем выполняет в нем соответствующие операции для дальнейшей оптимизации эффекта скольжения.

Язык кода:javascript
копировать
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)

val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager

val adapter = MyAdapter(dataList)
recyclerView.adapter = adapter

recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        super.onScrollStateChanged(recyclerView, newState)
        // Определите, является ли состояние прокрутки состоянием остановки прокрутки.
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
            startLoaidng()
        } else {
            // Выполните операции остановки загрузки, например остановку загрузки изображения и т. д.
            stopLoading()
        }
    }
})

предварительная загрузка

  1. Начать расчетExtraLayoutSpace

calculateExtraLayoutSpace Этот метод можно использовать для увеличения дополнительного пространства, зарезервированного RecyclerView, что помогает заранее загружать элементы за пределами экрана и избегать лагов во время скольжения.

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

Язык кода:javascript
копировать
class CustomLayoutManager : LinearLayoutManager {

    constructor(context: Context) : super(context)

    constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout)

    override fun calculateExtraLayoutSpace(state: RecyclerView.State, extraLayoutSpace: IntArray) {
        super.calculateExtraLayoutSpace(state, extraLayoutSpace)
        // обустройство дополнительного пространства измакета, которое можно динамически рассчитывать по мере необходимости
        extraLayoutSpace[0] = 200 
        extraLayoutSpace[1] = 200
    }
}
  1. Переопределить CollectAdjacentPrefetchPositions

collectAdjacentPrefetchPositionsМетодRecyclerViewсерединаизметод защиты,Используется для сбора предварительно выбранных местоположений, соседних с заданным местоположением. Этот метод в основном используется для механизма предварительной выборки RecyclerView.,Используется для существования предварительной выборки рядом с текущей позицией во время скольжения из данных.,Улучшите плавность скольжения.

ты можешьсуществовать НастроитьLayoutManagerсерединапереписатьcollectAdjacentPrefetchPositionsМетод достижения соседнего положенияизлогика предварительной выборки。

Язык кода:javascript
копировать
class CustomLayoutManager : LinearLayoutManager {

    constructor(context: Context) : super(context)

    constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout)

    override fun collectAdjacentPrefetchPositions(dx: Int, dy: Int, state: RecyclerView.State?, layoutPrefetchRegistry: LayoutPrefetchRegistry) {
        super.collectAdjacentPrefetchPositions(dx, dy, state, layoutPrefetchRegistry)

        // По направлению скольжения (dx, dy) Собрать соседние позиции предварительной выборки
        val anchorPos = findFirstVisibleItemPosition()
        if (dy > 0) {
            // Проведите пальцем вниз, чтобы предварительно загрузить следующие объекты:
            for (i in anchorPos + 1 until state?.itemCount ?: 0) {
                layoutPrefetchRegistry.addPosition(i, 0)
            }
        } else {
            // Проведите пальцем вверх, чтобы предварительно загрузить указанные выше элементы.
            for (i in anchorPos - 1 downTo 0) {
                layoutPrefetchRegistry.addPosition(i, 0)
            }
        }
    }
}

Оптимизация памяти

  1. Общий RecyclerViewPool

Если несколько RecycledView из Adapter Как и в случае с RecycledViewPool, вы можете использовать общий доступ к RecycledViewPool между RecyclerViews, чтобы повысить производительность.

Язык кода:javascript
копировать
// Создайте общий изRecycledViewPool.
val recycledViewPool = RecyclerView.RecycledViewPool()

// настройки Поделиться изRecycledViewPool на несколько RecyclerView
recyclerView1.setRecycledViewPool(recycledViewPool)
recyclerView2.setRecycledViewPool(recycledViewPool)

Этот подход особенно подходит для ситуаций, когда структура нескольких RecyclerViewPool очень схожа. Совместное использование RecycledViewPool может еще больше повысить производительность RecyclerView.

  1. Используйте Adaptor.setHasStableIds(true) для улучшения стабильности элемента.

настраиватьAdapterизsetHasStableIds(true)можно улучшитьItemизстабильность,Помогите RecyclerView лучше идентифицировать и повторно использовать ViewHolder.,Избегайте частого создания и удаления ViewHolder.,Уменьшите потребление памяти.

Язык кода:javascript
копировать
adapter.setHasStableIds(true)
  1. Используйте RecyclerView.setItemViewCacheSize(size) для настройки размера кэша

проходитьнастраиватьRecyclerViewизsetItemViewCacheSize(size)методнастраиватьразмер кэша,Может контролировать количество кэшированных ViewHolder в RecyclerView.,Избегайте слишком большого количества кэшей, занимающих слишком много памяти.

Язык кода:javascript
копировать
recyclerView.setItemViewCacheSize(20) // размер кэша настроек равен 20
  1. Общие события

Например событие клика,Можно создать общий объект прослушивателя,И дать ему настройки всем изItemView. Затем различайте и выполняйте различные операции на основе идентификатора. Это позволяет избежать создания объекта прослушивателя для каждого элемента.,оптимизация снизила потребление ресурсов.

Язык кода:javascript
копировать
// Общий объект прослушивателя
val itemClickListener = View.OnClickListener { view ->
    // Выполнение различных операций на основе идентификатора представления
    when (view.id) {
        R.id.button -> {
            // Выполнить действие по нажатию кнопки
        }
        R.id.imageView -> {
            // Выполнение операций щелчка изображения
        }
        // Другая обработка IDиз...
    }
}

// существованиеViewHolder для ItemViewнастройки, общие из прослушивателя
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    init {
        // Общий доступ для всех тех, кому нужна настройка ItemView
        itemView.setOnClickListener(itemClickListener)
    }
}
  1. Переопределить RecyclerView.onViewRecycled(holder) для переработки ресурсов

существовать onViewRecycled(holder: ViewHolder) 方法середина,Мы можем выполнить некоторые операции по освобождению ресурсов.,Например Освободите ресурсы изображения в ViewHolder、Удалить прослушиватели и т. д.,Чтобы связанные ресурсы могли быть освобождены вовремя, когда существующийViewHolder будет переработан.,Избегайте утечек памяти и непроизводительной траты ресурсов.

Язык кода:javascript
копировать
override fun onViewRecycled(holder: ViewHolder) {
    super.onViewRecycled(holder)
    // Освободите ресурсы изображения в ViewHolder
    holder.imageView.setImageDrawable(null)
    // Удалить прослушиватель в ViewHolder
    holder.itemView.setOnClickListener(null)
}

Подвести итог

Выбрав правильный изоптимизациямакет, Уменьшить рисунок、Скользящая оптимизация、предварительная загрузкаи Оптимизация памяти Стратегия,Может эффективно улучшить производительность RecyclerView.,Сделайте его существование гладким в любых ситуациях. существуютфактически в разработке,Также необходимо выбрать подходящую стратегию изоптимизации в соответствии с конкретной ситуацией.,и выполнить соответствующие испытания и настройки,Добиться наилучшего эффекта изпроизводительности.

boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода