Jetpack Compose оптимизация производительности списка

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

image

Я в своем время наткнулся на довольно интересное поведение composable функций в списках, тогда мне помогла статья с медиума и чтение книги по compose internals, ссылки на них я приложу в конце статьи. Решил поделиться, возможно кому-то это поможет)

Отображение списков распространенный кейс для большинства приложений и зачастую эти списки динамические, в них меняется контент, позиции элементов и т.д. Есть довольно быстрый способ оптимизировать ваш список в compose.
Но для начала рассмотрим, что такое «место вызова» (call site), composable функции.

Composable


Каждая функция, помеченная @Composable аннотацией будет иметь дополнительную информацию для kotlin компилятора о том, что она эмитит UI. Когда компилятор проходит по этой функции он добавляет информацию о месте ее вызова, эти данные являются уникальным идентификатором для composable функции.

Что такое место вызова (call site)


Информация о месте вызова необходима для переиспользования во время стадии recomposition дерева composable функций.

@Composable
fun Example(
    firstText: String,
    secondText: String
) {
    Column() {
        Text(firstText) // место вызова для composable с firstText
        Text(secondText) // место вызова для composable с secondText
    }
}


Так как обе composable функции вызываются в разных местах, то у каждой их них есть свой уникальный идентификатор места вызова.
Но давайте посмотрим на такой пример:

@Composable
fun Loop() {
    Column {
        for (num in 1..0) {
            Text(num.toString())
        }
    }
}


Можно заметить, что теперь место вызова всегда одинаковое, это нарушает правило уникального идентификатора. В таких кейсах по дефолту компилятор котлина добавляет к информации о месте вызова еще и позицию в списке. Это позволяет переиспользовать composable функции во время процесса recomposition.

Но у нас проблемы по коням Андрюха, у нас криминал.
Давайте представим, что список модифицируемый. Что произойдет если новый элемент добавится в начало списка? Место вызова каждой созданной composable функции зависело от позиции элемента в списке, так как все позиции поменялись теперь ни одно произведенное вычисление composable функций не может быть переиспользовано, хотя контент не менялся. Такое поведение стоит поправить.

Оптимизация через Key


Давайте предоставлять уникальную информацию для места вызова вместо компилятора

@Composable
fun Loop() {
    Column {
        for (someObj in ourList) {
            key(someObj.key) {
                Text(someObj)
            }
        }
    }
}


Теперь место вызова еще имеет информацию которую мы предоставляем через key. В таком кейсе при добавлении нового элемента в начало списка новая composable функция инициализируется только для этого айтема, все остальные заэмиченные composable функции будут переиспользованы.
Такую оптимизацию мы также можем добавить для LazyColumn и LazyRow:

@Composable
fun Loop() {
    LazyColumn(ourList, {someObject -> someObject.id}){
        Text(someObj)
    }
}

Список вдоховителей:


Статья, освещающая, данную тему на английском
Полезная книга по внутренностям compose
Источник: https://habr.com/ru/post/645799/


Интересные статьи

Интересные статьи

В июле Google выпустил стабильную версию Compose. Это вызвало большой интерес в сообществе. Все вокруг стали поговаривать, что эта технология захватит Android-разработку, и скоро все будут писать на C...
В этом материале речь пойдёт об оптимизациях, которые включает опция -ffast-math при компиляции кода, написанного на C или C++, с использованием GCC 11 для x86_64 Linux (при применении других языков, ...
В моём предыдущем материале речь шла о сравнении производительности ASP.NET Core-приложений, запускаемых в Windows и в среде Linux + Docker, работающих в службе приложений Azure. Эта тема...
Привет, читатель. Иногда для решении задачи приходится использовать Рекурсию, в которой есть свои плюсы и минусы. Я столкнулся с проблемой переполнения стека. Максимальная глубина рекурсии ог...
Привет, Хабр! Две недели назад мы выпустили GoLand 2019.1 и спешим рассказать вам о новинках этого релиза.