В разработке для Android RecyclerView — это часто используемый элемент управления списком, используемый для отображения больших объемов данных. Однако по мере увеличения объема данных производительность RecyclerView может снизиться, что приведет к таким проблемам, как задержки и утечки памяти. В этой статье будут представлены некоторые методы оптимизации, которые помогут вам повысить производительность RecyclerView, чтобы она оставалась бесперебойной при различных обстоятельствах.
Основные идеи оптимизации производительности RecyclerView можно свести к следующим аспектам:
Ниже приведены конкретные стратегии оптимизации для каждого из них.
Избегайте использования слишком большого количества вложенных макетов и сложных иерархий в макете элемента RecyclerView, что увеличит время и потребление ресурсов рендеринга. Попробуйте использовать простую структуру макета и рационально использовать эффективные макеты, такие как ConstraintLayout.
<!-- 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>
Используйте тег слияния, чтобы объединить несколько файлов макета в один, уменьшив уровни макета и повысив производительность рисования.
<!-- Используйте тег слияния для объединения макета -->
<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>
настраивать setHasFixedSize(true)
назад,RecyclerView предполагает, что высота всех элементов фиксирована.,Перерасчет не произойдет из-за изменений в Itemiz,избегатьrequestLayout
привести киз Пустая трата ресурсов。
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
recyclerView.setHasFixedSize(true)
Следует отметить, что использование setHasFixedSize(true)
Применяется ко всемItemВысота фиксирована и не меняется.из Состояние。еслиItemВысота не фиксирована или может меняться.,Этот метод следует избегать,В противном случае макет может отображаться ненормально.
Когда набор данных изменяется, использование DiffUtil для расчета разницы может уменьшить количество ненужных обновлений пользовательского интерфейса и повысить производительность. DiffUtil может эффективно вычислять различия наборов данных в фоновом потоке и применять результаты к RecyclerView.
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)
Если объем данных в списке очень велик, вы можете рассмотреть возможность загрузки страниц или загрузки данных только в пределах видимого диапазона, чтобы уменьшить использование памяти и время рендеринга.
// Загружать только видимый диапазон изданных
recyclerView.layoutManager?.setInitialPrefetchItemCount(10)
существуютViewHolderиз Этап создания,Выполните необходимые операции инициализации,Такие как настройки монитора и т.д.,избегатьсуществоватьonBindViewHolder()
середина进行耗时操作,Улучшение прокруткипроизводительность。
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
}
может пройти RecyclerView.addOnScrollListener(listener)
Метод добавляет прослушиватель прокрутки, а затем выполняет в нем соответствующие операции для дальнейшей оптимизации эффекта скольжения.
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()
}
}
})
calculateExtraLayoutSpace
Этот метод можно использовать для увеличения дополнительного пространства, зарезервированного RecyclerView, что помогает заранее загружать элементы за пределами экрана и избегать лагов во время скольжения.
тыможет пройтипереписатьcalculateExtraLayoutSpace
метод возврата дополнительныхиз Размер пространства,так чтоRecyclerViewсуществовать Во время скольженияпредварительная загрузка закадрового из Предмета.
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
}
}
collectAdjacentPrefetchPositions
МетодRecyclerViewсерединаизметод защиты,Используется для сбора предварительно выбранных местоположений, соседних с заданным местоположением. Этот метод в основном используется для механизма предварительной выборки RecyclerView.,Используется для существования предварительной выборки рядом с текущей позицией во время скольжения из данных.,Улучшите плавность скольжения.
ты можешьсуществовать НастроитьLayoutManagerсерединапереписатьcollectAdjacentPrefetchPositions
Метод достижения соседнего положенияизлогика предварительной выборки。
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)
}
}
}
}
Если несколько RecycledView
из Adapter
Как и в случае с RecycledViewPool, вы можете использовать общий доступ к RecycledViewPool между RecyclerViews, чтобы повысить производительность.
// Создайте общий изRecycledViewPool.
val recycledViewPool = RecyclerView.RecycledViewPool()
// настройки Поделиться изRecycledViewPool на несколько RecyclerView
recyclerView1.setRecycledViewPool(recycledViewPool)
recyclerView2.setRecycledViewPool(recycledViewPool)
Этот подход особенно подходит для ситуаций, когда структура нескольких RecyclerViewPool очень схожа. Совместное использование RecycledViewPool может еще больше повысить производительность RecyclerView.
настраиватьAdapterизsetHasStableIds(true)
можно улучшитьItemизстабильность,Помогите RecyclerView лучше идентифицировать и повторно использовать ViewHolder.,Избегайте частого создания и удаления ViewHolder.,Уменьшите потребление памяти.
adapter.setHasStableIds(true)
проходитьнастраиватьRecyclerViewизsetItemViewCacheSize(size)
методнастраиватьразмер кэша,Может контролировать количество кэшированных ViewHolder в RecyclerView.,Избегайте слишком большого количества кэшей, занимающих слишком много памяти.
recyclerView.setItemViewCacheSize(20) // размер кэша настроек равен 20
Например событие клика,Можно создать общий объект прослушивателя,И дать ему настройки всем изItemView. Затем различайте и выполняйте различные операции на основе идентификатора. Это позволяет избежать создания объекта прослушивателя для каждого элемента.,оптимизация снизила потребление ресурсов.
// Общий объект прослушивателя
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)
}
}
существовать onViewRecycled(holder: ViewHolder)
方法середина,Мы можем выполнить некоторые операции по освобождению ресурсов.,Например Освободите ресурсы изображения в ViewHolder、Удалить прослушиватели и т. д.,Чтобы связанные ресурсы могли быть освобождены вовремя, когда существующийViewHolder будет переработан.,Избегайте утечек памяти и непроизводительной траты ресурсов.
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
// Освободите ресурсы изображения в ViewHolder
holder.imageView.setImageDrawable(null)
// Удалить прослушиватель в ViewHolder
holder.itemView.setOnClickListener(null)
}
Выбрав правильный изоптимизациямакет, Уменьшить рисунок、Скользящая оптимизация、предварительная загрузкаи Оптимизация памяти Стратегия,Может эффективно улучшить производительность RecyclerView.,Сделайте его существование гладким в любых ситуациях. существуютфактически в разработке,Также необходимо выбрать подходящую стратегию изоптимизации в соответствии с конкретной ситуацией.,и выполнить соответствующие испытания и настройки,Добиться наилучшего эффекта изпроизводительности.