Диагностика проблем со стабильностью

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

Инспектор компоновки

В Android Studio инструмент Layout Inspector позволяет увидеть, какие компоненты Compose перекомпоновываются в вашем приложении. Он отображает количество перекомпоновок или пропусков компонентов в Compose.

Количество перекомпоновок и пропусков в инспекторе компоновки.

Отчеты компилятора Compose

Компилятор Compose может выводить результаты анализа стабильности для проверки. Используя эти данные, вы можете определить, какие из ваших компонуемых элементов можно пропустить, а какие — нет. В следующих подразделах кратко описано, как использовать эти отчеты, но для получения более подробной информации см. техническую документацию .

Настраивать

Отчеты компилятора Compose по умолчанию отключены. Вы можете активировать их с помощью флага компилятора. Точная настройка зависит от вашего проекта, но для проектов, использующих плагин Compose compiler gradle, вы можете добавить следующее в файл build.gradle каждого модуля.

  android { ... }

  composeCompiler {
    reportsDestination = layout.buildDirectory.dir("compose_compiler")
    metricsDestination = layout.buildDirectory.dir("compose_compiler")
  }

Теперь отчеты компилятора Compose будут генерироваться при сборке вашего проекта.

Пример выходных данных

Функция reportsDestination выводит три файла. Ниже приведены примеры выходных данных из JetSnack .

  • <modulename>-classes.txt : Отчет о стабильности классов в этом модуле. Пример .
  • <modulename>-composables.txt : Отчет о том, насколько легко перезапускать и пропускать компоненты модуля. Пример .
  • <modulename>-composables.csv : CSV версия отчета по составным элементам, которую можно импортировать в электронную таблицу или использовать для обработки данных с помощью скрипта. Пример

Отчет о компонуемых компонентах

Файл composables.txt содержит подробную информацию о каждой компонуемой функции для данного модуля, включая стабильность их параметров, а также возможность перезапуска или пропуска этих функций. Ниже приведён гипотетический пример из JetSnack :

restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun SnackCollection(
  stable snackCollection: SnackCollection
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
  stable index: Int = @static 0
  stable highlight: Boolean = @static true
)

Этот компонент SnackCollection полностью перезапускаем, его можно пропустить, и он стабилен. Это, как правило, предпочтительно, хотя и не обязательно.

Или рассмотрим другой пример.

restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  stable index: Int
  unstable snacks: List<Snack>
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
)

Параметр HighlightedSnacks нельзя пропустить. Compose никогда не пропускает его при повторной композиции. Это происходит даже если ни один из его параметров не изменился. Причина этого — unstable параметр snacks .

Отчет о занятиях

Файл classes.txt содержит аналогичный отчет о классах в данном модуле. Ниже приведен фрагмент кода, демонстрирующий вывод для класса Snack :

unstable class Snack {
  stable val id: Long
  stable val name: String
  stable val imageUrl: String
  stable val price: Long
  stable val tagline: String
  unstable val tags: Set<String>
  <runtime stability> = Unstable
}

Для справки, ниже приведено определение слова Snack :

data class Snack(
    val id: Long,
    val name: String,
    val imageUrl: String,
    val price: Long,
    val tagline: String = "",
    val tags: Set<String> = emptySet()
)

Компилятор Compose пометил Snack как нестабильный. Это связано с тем, что тип параметра tagsSet<String> . Это неизменяемый тип, поскольку он не является MutableSet . Однако стандартные классы коллекций, такие как Set , List и Map в конечном итоге являются интерфейсами. Таким образом, базовая реализация может оставаться изменяемой.

Например, можно написать val set: Set<String> = mutableSetOf("foo") . Переменная является константой, и её объявленный тип не является изменяемым, но её реализация всё ещё изменяема. Компилятор Compose не может быть уверен в неизменяемости этого класса, поскольку он видит только объявленный тип. Поэтому он помечает tags как нестабильные.