Connect with us

Разработка

Осваиваем ViewModel в Android: «можно» и «нельзя» — Часть 3

Если вы используете ViewModels, помните об этих вещах для повышения качества кода.

Фото аватара

Опубликовано

/

     
     

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

В предыдущих частях мы обсудили:

  1. Избегайте инициализации состояния в блоке init{}.
  2. Избегайте раскрытия мутабельных состояний.
  3. Используйте update{} при использовании MutableStateFlows.

В этой части мы обсудим 4 и 5 пункты из списка:

  1. Старайтесь не импортировать зависимости Android в ViewModel.
  2. Лениво внедряйте зависимости в конструктор.
  3. Примите более реактивное и менее императивное программирование.
  4. Избегайте инициализации ViewModel из внешнего мира.
  5. Избегайте передачи параметров из внешнего мира.
  6. Избегайте жесткого прописывания диспетчеров корутинов.
  7. Проводите модульное тестирование своих ViewModel.
  8. Избегайте раскрытия suspended функций.
  9. Используйте обратный вызов onCleared() во ViewModel.
  10. Обрабатывайте смерть процесса и изменения конфигурации.
  11. Вставляйте UseCases, которые вызывают Репозитории, которые, в свою очередь, вызывают DataSource.
  12. Включайте в ViewModel только доменные объекты.
  13. Используйте операторы shareIn() и stateIn(), чтобы избежать многократных обращений к восходящему потоку.

4. Старайтесь не импортировать зависимости Android во ViewModel

Рекомендация избегать импорта зависимостей Android во ViewModel, за особыми исключениями для таких классов, как LiveData и его трансформеров, основана на принципах чистой архитектуры и тестируемости. Ниже мы объясним, что это значит и почему это важно.

1. Разделение ответственности

  • Зависимости Android, такие как R (ресурсы) и другие классы Android-фреймворка, напрямую связаны с операционной системой Android и ее контекстом. Эти классы отвечают за управление элементами пользовательского интерфейса, доступ к ресурсам Android (строки, ресурсы drawable и т. д.) и взаимодействие с системой Android (намерения, контекст и т. д.).
  • Не допуская зависимости во ViewModel, вы обеспечиваете четкое разделение задач. ViewModel не нужно знать о контексте Android или элементах пользовательского интерфейса, чтобы выполнять свою работу, которая заключается в управлении данными для пользовательского интерфейса.

Но что, если мне нужно выдать какую-то строку из вью-модели как часть состояния?

Для таких случаев идеальным вариантом будет использование изолированного (sealed) интерфейса Kotlin, подробнее об этом читайте в этой статье.

2. Тестируемость

  • Зависимости Android могут усложнить модульное тестирование, поскольку часто требуют наличия работающего окружения Android (например, эмулятора или физического устройства). Это может замедлить тестирование и сделать его более хрупким.
  • ViewModel без зависимостей от Android можно тестировать на JVM без использования среды Android, что приводит к более быстрым и надежным тестам. LiveData и ее трансформаторы являются исключением, поскольку они разработаны с учетом жизненного цикла и могут быть легко мокированы или наблюдаемы в тестах.

3. Переносимость

Код, который не зависит напрямую от фреймворка Android, более переносим и прост в сопровождении. Его можно повторно использовать в разных частях приложения или даже в других проектах с минимальными изменениями. И даже в будущем вью-модели можно будет легко заменить, например, на Circuit Presenters из Slack, чтобы перенести вашу кодовую базу на Kotlin MultiPlatform.

А как же LiveData и трансформеры

  • LiveData и ее трансформеры (например, Transformations.map и Transformations.switchMap) предназначены для использования во ViewModel. Они учитывают жизненный цикл, позволяя ViewModel обновлять пользовательский интерфейс безопасным способом, реагируя на события жизненных циклов Активити и Фрагментов.
  • Эти классы не привязывают вашу ViewModel к конкретным элементам или ресурсам пользовательского интерфейса Android. Вместо этого они предоставляют ViewModel механизм для изменения данных с учетом жизненного цикла, который может наблюдать UI-слой.

5. Лениво внедряйте зависимости в конструктор

Инжектирование зависимостей непосредственно в конструкторы ViewModel без ленивой инициализации может привести к:

  1. увеличению времени запуска
  2. повышенному использованию памяти
  3. излишней загрузке процессора

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

Неиспользование ленивой инициализации для зависимостей в конструкторах ViewModel может повлиять на производительность и использование ресурсов Android-приложения, особенно во время запуска или при создании экземпляров этих ViewModel. Ниже обсудим, как неленивая инъекция сравнивается с ленивой и почему последняя часто предпочтительнее в определенных сценариях.

Когда следует использовать ленивую инициализацию

  • Большие или редко используемые зависимости: Если ViewModel имеет большие зависимости или те, к которым редко обращаются, ленивая инициализация будет полезна, поскольку она позволяет избежать затрат на инициализацию этих ресурсов до тех пор, пока они действительно не понадобятся.
  • Условные зависимости: Для зависимостей, которые нужны только при определенных условиях (например, на основе действий пользователя или определенных состояний приложения), ленивая инициализация предотвращает ненужную настройку.

Пример

@HiltViewModel
class BookViewModel @Inject constructor(
    @IoDispatcher private val ioDispatcher: CoroutineDispatcher,
    private val bookmarkUseCase: dagger.Lazy<BookmarkUsecase>,

Представьте, что в вашей ViewModel есть действие с закладкой, которое сработает, если пользователь нажмет на кнопку закладки. Для этой зависимости, которая внедряется через конструктор BookViewModel, мы можем использовать ленивую инъекцию, которая отложит создание Usecase до тех пор, пока он не понадобится.

Источник

Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.
Advertisement

Наши партнеры:

LEGALBET

Мобильные приложения для ставок на спорт
Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: