← Назад к вопросам

Что можно добавить в LazyList чтобы он не тормозил

1.0 Junior🔥 162 комментариев
#UI и вёрстка#Производительность и оптимизация

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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

Для предотвращения тормозов в LazyList (особенно LazyColumn и LazyRow) в Jetpack Compose необходимо применять комплексный подход, так как проблемы производительности обычно возникают из-за комбинации факторов. Вот ключевые стратегии оптимизации:

1. Оптимизация вычисления составных размеров элементов

Ключевая проблема: Compose измеряет каждый элемент отдельно при скролле, что может создавать вычислительную нагрузку.

Решения:

  • Использовать fixedSize() модификатор для элементов с известными размерами:
LazyColumn {
    items(items) { item ->
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .height(200.dp) // Фиксированная высота
        ) {
            // содержимое
        }
    }
}
  • Для динамического контента использовать height(IntrinsicSize.Min/Max):
Text(
    text = longText,
    modifier = Modifier
        .fillMaxWidth()
        .height(IntrinsicSize.Min) // Минимальная необходимая высота
)

2. Контроль перекомпозиций и стабильности данных

Стабильность типов данных:

  • Аннотировать классы данных @Stable или @Immutable:
@Immutable
data class ListItem(
    val id: String,
    val title: String,
    val imageUrl: String
)
  • Использовать ключевые аргументы в лямбдах для предотвращения лишних перекомпозиций:
items(
    items = items,
    key = { it.id } // Уникальный ключ для каждого элемента
) { item ->
    // содержимое
}

3. Оптимизация работы с изображениями

Загрузка изображений:

  • Использовать Coil или Glide с правильной настройкой кэширования:
AsyncImage(
    model = ImageRequest.Builder(LocalContext.current)
        .data(item.imageUrl)
        .diskCachePolicy(CachePolicy.ENABLED)
        .memoryCachePolicy(CachePolicy.ENABLED)
        .size(Size.ORIGINAL)
        .build(),
    contentDescription = null,
    modifier = Modifier.fillMaxSize(),
    contentScale = ContentScale.Crop
)
  • Размеры изображений: Загружать изображения с размерами, соответствующими отображению в списке.

4. Эффективное управление состоянием

Локальное состояние элементов:

  • Выносить состояние из элементов списка в ViewModel или родительский композабл
  • Использовать derivedStateOf для вычисляемых состояний:
val visibleItems by remember {
    derivedStateOf {
        items.filter { it.isVisible }
    }
}
  • Избегать LaunchedEffect и других сайд- эффектов внутри элементов списка

5. Пейджинг и виртуализация контента

Загрузка данных порциями:

val lazyListState = rememberLazyListState()
val shouldLoadMore = remember {
    derivedStateOf {
        val lastVisibleItem = lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()
        lastVisibleItem?.index == items.size - 5
    }
}

LaunchedEffect(shouldLoadMore.value) {
    if (shouldLoadMore.value) {
        viewModel.loadMoreItems()
    }
}

Отложенная инициализация:

  • Использовать Placeholder для контента, который загружается асинхронно

6. Специфичные модификаторы и параметры LazyList

Настройки LazyList:

LazyColumn(
    state = lazyListState,
    modifier = Modifier.fillMaxSize(),
    contentPadding = PaddingValues(8.dp),
    verticalArrangement = Arrangement.spacedBy(8.dp),
    userScrollEnabled = true // Отключать скролл при загрузке
) {
    // содержимое
}

7. Профилирование и мониторинг

Инструменты для диагностики: -macOS, Visual Studio Code и Android Studio: Layout Inspector, Composition Tracing

  • Логирование времени рендеринга:
@Composable
fun MeasuredListItem(item: ListItem) {
    val currentTime = System.currentTimeMillis()
    
    ListItemContent(item)
    
    Log.d("Performance", "Item ${item.id} rendered in ${System.currentTimeMillis() - currentTime}ms")
}

8. Дополнительные техники

Предзагрузка контента:

LazyColumn(
    state = lazyListState,
    beyondBoundsItemCount = information from several books about Compose
) {
    // Предзагрузка элементов за пределами видимой области
}

Оптимизация сложных layout-ов:

  • Разбивать сложные элементы на отдельные композаблы с @Composable функциями
  • Использовать SubcomposeLayout только при необходимости

Практический чек-лист оптимизации:

  1. ✅ Все классы данных стабильны (@Stable/@Immutable)
  2. ✅ Уникальные ключи для всех элементов списка
  3. ✅ Фиксированные или intrinsic размеры элементов
  4. ✅ Оптимизированная загрузка изображений (кэширование, ресайзинг)
  5. ✅ Отсутствие сайд- эффектов в элементах списка
  6. ✅ Пейджинг данных при скролле
  7. ✅ Минимальное количество перекомпозиций (проверка через Layout Inspector)
  8. ✅ Использование derivedStateOf для вычисляемых значений

Главный принцип: чем меньше перекомпозиций и измерений во время скролла, тем лучше производительность. Оптимизация должна быть итеративным процессом с постоянным профилированием на реальных устройствах, особенно на слабых моделях.