Рекомендации по архитектуре Android

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

Рекомендации ниже сгруппированы по темам. У каждого есть приоритет, который отражает, насколько сильно его рекомендует команда. Список приоритетов выглядит следующим образом:

  • Настоятельно рекомендуется: вам следует применять эту практику, если она не противоречит фундаментальному вашему подходу.
  • Рекомендуется: эта практика может улучшить ваше приложение.
  • Необязательно: эта практика может улучшить ваше приложение в определенных обстоятельствах.

Многоуровневая архитектура

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

Рекомендация Описание
Используйте четко определенный уровень данных . Уровень данных предоставляет данные приложения остальной части приложения и содержит большую часть бизнес-логики вашего приложения.
  • Вам следует создавать репозитории , даже если они содержат только один источник данных.
  • В небольших приложениях вы можете разместить типы слоев данных в пакете data или модуле.
Используйте четко определенный уровень пользовательского интерфейса . Уровень пользовательского интерфейса отображает данные приложения на экране и служит основной точкой взаимодействия с пользователем.
  • В небольших приложениях вы можете разместить типы слоев данных в пакете или модуле ui .
Дополнительные рекомендации по созданию слоев пользовательского интерфейса можно найти здесь .
Уровень данных должен предоставлять данные приложения с помощью репозитория.

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

  • Базы данных, хранилище данных, SharedPreferences, API Firebase.
  • Поставщики местоположения GPS.
  • Поставщики данных Bluetooth.
  • Поставщик статуса сетевого подключения.
Используйте сопрограммы и потоки . Используйте сопрограммы и потоки для взаимодействия между уровнями.

Больше лучших практик сопрограмм здесь .

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

Уровень пользовательского интерфейса

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

Рекомендация Описание
Следуйте однонаправленному потоку данных (UDF) . Следуйте принципам однонаправленного потока данных (UDF) , согласно которым модели представления предоставляют состояние пользовательского интерфейса с помощью шаблона наблюдателя и получают действия от пользовательского интерфейса посредством вызовов методов.
Используйте AAC ViewModels, если их преимущества применимы к вашему приложению. Используйте AAC ViewModels для обработки бизнес-логики и получения данных приложения, чтобы представить состояние пользовательского интерфейса в пользовательском интерфейсе (Compose или представления Android).

Дополнительные рекомендации по ViewModel см. здесь.

Ознакомьтесь с преимуществами ViewModels здесь.

Используйте коллекцию состояний пользовательского интерфейса с учетом жизненного цикла. Соберите состояние пользовательского интерфейса из пользовательского интерфейса с помощью соответствующего построителя сопрограмм, учитывающего жизненный цикл: repeatOnLifecycle в системе View и collectAsStateWithLifecycle в Jetpack Compose.

Узнайте больше о repeatOnLifecycle .

Узнайте больше о collectAsStateWithLifecycle .

Не отправляйте события из ViewModel в пользовательский интерфейс. Немедленно обработайте событие в ViewModel и вызовите обновление состояния с результатом обработки события. Подробнее о событиях пользовательского интерфейса здесь .
Используйте приложение с одним действием. Используйте фрагменты навигации или компоновку навигации для навигации между экранами и создания глубоких ссылок на ваше приложение, если ваше приложение имеет более одного экрана.
Используйте Jetpack Compose . Используйте Jetpack Compose для создания новых приложений для телефонов, планшетов, складных устройств и Wear OS.

В следующем фрагменте показано, как собирать состояние пользовательского интерфейса с учетом жизненного цикла:

Просмотры

class MyFragment : Fragment() {

    private val viewModel: MyViewModel by viewModel()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Process item
                }
            }
        }
    }
}

Сочинить

@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}

Модель просмотра

Модели представления отвечают за предоставление состояния пользовательского интерфейса и доступ к уровню данных. Вот некоторые рекомендации для ViewModels:

Рекомендация Описание
Модели ViewModels не должны зависеть от жизненного цикла Android. Модели ViewModels не должны содержать ссылки на какой-либо тип, связанный с жизненным циклом. Не передавайте Activity, Fragment, Context или Resources в качестве зависимости. Если чему-то нужен Context в ViewModel, вам следует тщательно оценить, находится ли он на правильном уровне.
Используйте сопрограммы и потоки .

ViewModel взаимодействует со слоями данных или домена, используя:

  • Kotlin потоки для получения данных приложения,
  • suspend функции для выполнения действий с использованием viewModelScope .
Используйте ViewModels на уровне экрана.

Не используйте ViewModels в повторно используемых частях пользовательского интерфейса. Вы должны использовать ViewModels в:

  • Компонуемые элементы на уровне экрана,
  • Действия/фрагменты в представлениях,
  • Пункты назначения или графики при использовании Jetpack Navigation .
Используйте классы-держатели простого состояния в повторно используемых компонентах пользовательского интерфейса. Используйте классы-держатели простого состояния для решения сложных задач в повторно используемых компонентах пользовательского интерфейса. Поступая таким образом, государство можно поднять и контролировать извне.
Не используйте AndroidViewModel . Используйте класс ViewModel , а не AndroidViewModel . Класс Application не следует использовать в ViewModel. Вместо этого переместите зависимость в пользовательский интерфейс или на уровень данных.
Раскройте состояние пользовательского интерфейса. Модели ViewModels должны предоставлять данные пользовательскому интерфейсу через одно свойство, называемое uiState . Если пользовательский интерфейс отображает несколько несвязанных фрагментов данных, виртуальная машина может предоставить несколько свойств состояния пользовательского интерфейса .
  • Вы должны сделать uiState StateFlow .
  • Вам следует создать uiState с помощью оператора stateIn с политикой WhileSubscribed(5000) (пример) , если данные поступают в виде потока данных из других уровней иерархии.
  • В более простых случаях, когда нет потоков данных, поступающих с уровня данных, допустимо использовать MutableStateFlow представленный как неизменяемый StateFlow (пример) .
  • Вы можете выбрать ${Screen}UiState как класс данных, который может содержать данные, ошибки и сигналы загрузки. Этот класс также может быть запечатанным классом, если разные состояния являются исключительными.

В следующем фрагменте показано, как предоставить состояние пользовательского интерфейса из ViewModel:

@HiltViewModel
class BookmarksViewModel @Inject constructor(
    newsRepository: NewsRepository
) : ViewModel() {

    val feedState: StateFlow<NewsFeedUiState> =
        newsRepository
            .getNewsResourcesStream()
            .mapToFeedState(savedNewsResourcesState)
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5_000),
                initialValue = NewsFeedUiState.Loading
            )

    // ...
}

Жизненный цикл

Ниже приведены некоторые рекомендации по работе с жизненным циклом Android :

Рекомендация Описание
Не переопределяйте методы жизненного цикла в действиях или фрагментах. Не переопределяйте методы жизненного цикла, такие как onResume в действиях или фрагментах. Вместо этого используйте LifecycleObserver . Если приложению необходимо выполнить работу, когда жизненный цикл достигает определенного Lifecycle.State , используйте API repeatOnLifecycle .

В следующем фрагменте показано, как выполнять операции в определенном состоянии жизненного цикла:

Просмотры

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                // ...
            }
            override fun onPause(owner: LifecycleOwner) {
                // ...
            }
        }
    }
}

Сочинить

@Composable
fun MyApp() {

    val lifecycleOwner = LocalLifecycleOwner.current
    DisposableEffect(lifecycleOwner, ...) {
        val lifecycleObserver = object : DefaultLifecycleObserver {
            override fun onStop(owner: LifecycleOwner) {
                // ...
            }
        }

        lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
        }
    }
}

Обработка зависимостей

Существует несколько рекомендаций, которые следует соблюдать при управлении зависимостями между компонентами:

Рекомендация Описание
Используйте внедрение зависимостей . Используйте лучшие практики внедрения зависимостей , в основном внедрение конструктора, когда это возможно.
При необходимости перейдите к компоненту. Область действия — контейнер зависимостей , если тип содержит изменяемые данные, которые необходимо совместно использовать, или тип требует больших затрат на инициализацию и широко используется в приложении.
Используйте Хилт . Используйте Hilt или ручное внедрение зависимостей в простых приложениях. Используйте Hilt , если ваш проект достаточно сложен. Например, если у вас есть:
  • Несколько экранов с ViewModels — интеграция
  • Использование WorkManager — интеграция
  • Расширенное использование навигации, например ViewModels, привязанных к навигационному графу, — интеграция.

Тестирование

Ниже приведены некоторые рекомендации по тестированию :

Рекомендация Описание
Знайте, что тестировать .

Если проект не такой же простой, как приложение hello world, вам следует протестировать его, как минимум, с помощью:

  • Модульное тестирование моделей представлений, включая потоки.
  • Объекты уровня данных модульного теста. То есть репозитории и источники данных.
  • Тесты навигации пользовательского интерфейса, полезные в качестве регрессионных тестов в CI.
Предпочитайте подделки издевательствам. Подробнее читайте в разделе «Использование тестовых двойников» в документации Android .
Тестирование StateFlows. При тестировании StateFlow :

Для получения дополнительной информации ознакомьтесь с руководством «Что тестировать в Android DAC» .

Модели

Вам следует соблюдать следующие рекомендации при разработке моделей в ваших приложениях:

Рекомендация Описание
Создавайте модели для каждого слоя в сложных приложениях.

В сложных приложениях создавайте новые модели в разных слоях или компонентах, когда это имеет смысл. Рассмотрим следующие примеры:

  • Удаленный источник данных может сопоставить модель, которую он получает по сети, с более простым классом, содержащим только те данные, которые нужны приложению.
  • Репозитории могут сопоставлять модели DAO с более простыми классами данных, используя только ту информацию, которая необходима уровню пользовательского интерфейса.
  • ViewModel может включать модели уровня данных в классы UiState .

Соглашения об именах

При присвоении имени вашей кодовой базе вы должны учитывать следующие рекомендации:

Рекомендация Описание
Методы именования.
Необязательный
Методы должны быть глагольной группой. Например, makePayment() .
Именование свойств.
Необязательный
Свойства должны быть существительными. Например, inProgressTopicSelection .
Именование потоков данных.
Необязательный
Когда класс предоставляет поток Flow, LiveData или любой другой поток, соглашение об именах — get{model}Stream() . Например, getAuthorStream(): Flow<Author> Если функция возвращает список моделей, имя модели должно быть во множественном числе: getAuthorsStream(): Flow<List<Author>>
Именование реализаций интерфейсов.
Необязательный
Имена реализаций интерфейсов должны быть осмысленными. Используйте префикс Default , если лучшее имя не найдено. Например, для интерфейса NewsRepository у вас может быть OfflineFirstNewsRepository или InMemoryNewsRepository . Если вы не можете найти хорошее имя, используйте DefaultNewsRepository . Поддельные реализации должны иметь префикс Fake , как в FakeAuthorsRepository .
,

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

Рекомендации ниже сгруппированы по темам. У каждого есть приоритет, который отражает, насколько сильно его рекомендует команда. Список приоритетов выглядит следующим образом:

  • Настоятельно рекомендуется: вам следует применять эту практику, если она не противоречит фундаментальному вашему подходу.
  • Рекомендуется: эта практика может улучшить ваше приложение.
  • Необязательно: эта практика может улучшить ваше приложение в определенных обстоятельствах.

Многоуровневая архитектура

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

Рекомендация Описание
Используйте четко определенный уровень данных . Уровень данных предоставляет данные приложения остальной части приложения и содержит большую часть бизнес-логики вашего приложения.
  • Вам следует создавать репозитории , даже если они содержат только один источник данных.
  • В небольших приложениях вы можете разместить типы слоев данных в пакете data или модуле.
Используйте четко определенный уровень пользовательского интерфейса . Уровень пользовательского интерфейса отображает данные приложения на экране и служит основной точкой взаимодействия с пользователем.
  • В небольших приложениях вы можете разместить типы слоев данных в пакете или модуле ui .
Дополнительные рекомендации по созданию слоев пользовательского интерфейса можно найти здесь .
Уровень данных должен предоставлять данные приложения с помощью репозитория.

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

  • Базы данных, хранилище данных, SharedPreferences, API Firebase.
  • Поставщики местоположения GPS.
  • Поставщики данных Bluetooth.
  • Поставщик статуса сетевого подключения.
Используйте сопрограммы и потоки . Используйте сопрограммы и потоки для взаимодействия между уровнями.

Больше лучших практик сопрограмм здесь .

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

Уровень пользовательского интерфейса

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

Рекомендация Описание
Следуйте однонаправленному потоку данных (UDF) . Следуйте принципам однонаправленного потока данных (UDF) , согласно которым модели представления предоставляют состояние пользовательского интерфейса с помощью шаблона наблюдателя и получают действия от пользовательского интерфейса посредством вызовов методов.
Используйте AAC ViewModels, если их преимущества применимы к вашему приложению. Используйте AAC ViewModels для обработки бизнес-логики и получения данных приложения, чтобы представить состояние пользовательского интерфейса в пользовательском интерфейсе (Compose или представления Android).

Дополнительные рекомендации по ViewModel см. здесь.

Ознакомьтесь с преимуществами ViewModels здесь.

Используйте коллекцию состояний пользовательского интерфейса с учетом жизненного цикла. Соберите состояние пользовательского интерфейса из пользовательского интерфейса с помощью соответствующего построителя сопрограмм, учитывающего жизненный цикл: repeatOnLifecycle в системе View и collectAsStateWithLifecycle в Jetpack Compose.

Узнайте больше о repeatOnLifecycle .

Узнайте больше о collectAsStateWithLifecycle .

Не отправляйте события из ViewModel в пользовательский интерфейс. Немедленно обработайте событие в ViewModel и вызовите обновление состояния с результатом обработки события. Подробнее о событиях пользовательского интерфейса здесь .
Используйте приложение с одним действием. Используйте фрагменты навигации или компоновку навигации для навигации между экранами и создания глубоких ссылок на ваше приложение, если ваше приложение имеет более одного экрана.
Используйте Jetpack Compose . Используйте Jetpack Compose для создания новых приложений для телефонов, планшетов, складных устройств и Wear OS.

В следующем фрагменте показано, как собирать состояние пользовательского интерфейса с учетом жизненного цикла:

Просмотры

class MyFragment : Fragment() {

    private val viewModel: MyViewModel by viewModel()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Process item
                }
            }
        }
    }
}

Сочинить

@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}

Модель представления

Модели представления отвечают за предоставление состояния пользовательского интерфейса и доступ к уровню данных. Вот некоторые рекомендации для ViewModels:

Рекомендация Описание
Модели ViewModels не должны зависеть от жизненного цикла Android. Модели ViewModels не должны содержать ссылки на какой-либо тип, связанный с жизненным циклом. Не передавайте Activity, Fragment, Context или Resources в качестве зависимости. Если чему-то нужен Context в ViewModel, вам следует тщательно оценить, находится ли он на правильном уровне.
Используйте сопрограммы и потоки .

ViewModel взаимодействует со слоями данных или домена, используя:

  • Kotlin потоки для получения данных приложения,
  • suspend функции для выполнения действий с использованием viewModelScope .
Используйте ViewModels на уровне экрана.

Не используйте ViewModels в повторно используемых частях пользовательского интерфейса. Вы должны использовать ViewModels в:

  • Компонуемые элементы на уровне экрана,
  • Действия/фрагменты в представлениях,
  • Пункты назначения или графики при использовании Jetpack Navigation .
Используйте классы-держатели простого состояния в повторно используемых компонентах пользовательского интерфейса. Используйте классы-держатели простого состояния для решения сложных задач в повторно используемых компонентах пользовательского интерфейса. Поступая таким образом, государство можно поднять и контролировать извне.
Не используйте AndroidViewModel . Используйте класс ViewModel , а не AndroidViewModel . Класс Application не следует использовать в ViewModel. Вместо этого переместите зависимость в пользовательский интерфейс или на уровень данных.
Раскройте состояние пользовательского интерфейса. Модели ViewModels должны предоставлять данные пользовательскому интерфейсу через одно свойство, называемое uiState . Если пользовательский интерфейс отображает несколько несвязанных фрагментов данных, виртуальная машина может предоставить несколько свойств состояния пользовательского интерфейса .
  • Вы должны сделать uiState StateFlow .
  • Вам следует создать uiState с помощью оператора stateIn с политикой WhileSubscribed(5000) (пример) , если данные поступают в виде потока данных из других уровней иерархии.
  • В более простых случаях, когда нет потоков данных, поступающих с уровня данных, допустимо использовать MutableStateFlow представленный как неизменяемый StateFlow (пример) .
  • Вы можете выбрать ${Screen}UiState как класс данных, который может содержать данные, ошибки и сигналы загрузки. Этот класс также может быть запечатанным классом, если разные состояния являются исключительными.

В следующем фрагменте показано, как предоставить состояние пользовательского интерфейса из ViewModel:

@HiltViewModel
class BookmarksViewModel @Inject constructor(
    newsRepository: NewsRepository
) : ViewModel() {

    val feedState: StateFlow<NewsFeedUiState> =
        newsRepository
            .getNewsResourcesStream()
            .mapToFeedState(savedNewsResourcesState)
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5_000),
                initialValue = NewsFeedUiState.Loading
            )

    // ...
}

Жизненный цикл

Ниже приведены некоторые рекомендации по работе с жизненным циклом Android :

Рекомендация Описание
Не переопределяйте методы жизненного цикла в действиях или фрагментах. Не переопределяйте методы жизненного цикла, такие как onResume в действиях или фрагментах. Вместо этого используйте LifecycleObserver . Если приложению необходимо выполнить работу, когда жизненный цикл достигает определенного Lifecycle.State , используйте API repeatOnLifecycle .

В следующем фрагменте показано, как выполнять операции в определенном состоянии жизненного цикла:

Просмотры

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                // ...
            }
            override fun onPause(owner: LifecycleOwner) {
                // ...
            }
        }
    }
}

Сочинить

@Composable
fun MyApp() {

    val lifecycleOwner = LocalLifecycleOwner.current
    DisposableEffect(lifecycleOwner, ...) {
        val lifecycleObserver = object : DefaultLifecycleObserver {
            override fun onStop(owner: LifecycleOwner) {
                // ...
            }
        }

        lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
        }
    }
}

Обработка зависимостей

Существует несколько рекомендаций, которые следует соблюдать при управлении зависимостями между компонентами:

Рекомендация Описание
Используйте внедрение зависимостей . Используйте лучшие практики внедрения зависимостей , в основном внедрение конструктора, когда это возможно.
При необходимости перейдите к компоненту. Область действия — контейнер зависимостей , если тип содержит изменяемые данные, которые необходимо совместно использовать, или тип требует больших затрат на инициализацию и широко используется в приложении.
Используйте Хилт . Используйте Hilt или ручное внедрение зависимостей в простых приложениях. Используйте Hilt , если ваш проект достаточно сложен. Например, если у вас есть:
  • Несколько экранов с ViewModels — интеграция
  • Использование WorkManager — интеграция
  • Расширенное использование навигации, например ViewModels, привязанных к навигационному графу, — интеграция.

Тестирование

Ниже приведены некоторые рекомендации по тестированию :

Рекомендация Описание
Знайте, что тестировать .

Если проект не такой же простой, как приложение hello world, вам следует протестировать его, как минимум, с помощью:

  • Модульное тестирование моделей представлений, включая потоки.
  • Объекты уровня данных модульного теста. То есть репозитории и источники данных.
  • Тесты навигации пользовательского интерфейса, полезные в качестве регрессионных тестов в CI.
Предпочитайте подделки издевательствам. Подробнее читайте в разделе «Использование тестовых двойников» в документации Android .
Тестирование StateFlows. При тестировании StateFlow :

Для получения дополнительной информации ознакомьтесь с руководством «Что тестировать в Android DAC» .

Модели

Вам следует соблюдать следующие рекомендации при разработке моделей в ваших приложениях:

Рекомендация Описание
Создавайте модели для каждого слоя в сложных приложениях.

В сложных приложениях создавайте новые модели в разных слоях или компонентах, когда это имеет смысл. Рассмотрим следующие примеры:

  • Удаленный источник данных может сопоставить модель, которую он получает по сети, с более простым классом, содержащим только те данные, которые нужны приложению.
  • Репозитории могут сопоставлять модели DAO с более простыми классами данных, используя только ту информацию, которая необходима уровню пользовательского интерфейса.
  • ViewModel может включать модели уровня данных в классы UiState .

Соглашения об именах

При присвоении имени вашей кодовой базе вы должны учитывать следующие рекомендации:

Рекомендация Описание
Методы именования.
Необязательный
Методы должны быть глагольной группой. Например, makePayment() .
Именование свойств.
Необязательный
Свойства должны быть существительными. Например, inProgressTopicSelection .
Именование потоков данных.
Необязательный
Когда класс предоставляет поток Flow, LiveData или любой другой поток, соглашение об именах — get{model}Stream() . Например, getAuthorStream(): Flow<Author> Если функция возвращает список моделей, имя модели должно быть во множественном числе: getAuthorsStream(): Flow<List<Author>>
Именование реализаций интерфейсов.
Необязательный
Имена реализаций интерфейсов должны быть осмысленными. Используйте префикс Default , если лучшее имя не найдено. Например, для интерфейса NewsRepository у вас может быть OfflineFirstNewsRepository или InMemoryNewsRepository . Если вы не можете найти хорошее имя, используйте DefaultNewsRepository . Поддельные реализации должны иметь префикс Fake , как в FakeAuthorsRepository .
,

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

Рекомендации ниже сгруппированы по темам. У каждого есть приоритет, который отражает, насколько сильно его рекомендует команда. Список приоритетов выглядит следующим образом:

  • Настоятельно рекомендуется: вам следует применять эту практику, если она не противоречит фундаментальному вашему подходу.
  • Рекомендуется: эта практика может улучшить ваше приложение.
  • Необязательно: эта практика может улучшить ваше приложение в определенных обстоятельствах.

Многоуровневая архитектура

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

Рекомендация Описание
Используйте четко определенный уровень данных . Уровень данных предоставляет данные приложения остальной части приложения и содержит большую часть бизнес-логики вашего приложения.
  • Вам следует создавать репозитории , даже если они содержат только один источник данных.
  • В небольших приложениях вы можете разместить типы слоев данных в пакете data или модуле.
Используйте четко определенный уровень пользовательского интерфейса . Уровень пользовательского интерфейса отображает данные приложения на экране и служит основной точкой взаимодействия с пользователем.
  • В небольших приложениях вы можете разместить типы слоев данных в пакете или модуле ui .
Дополнительные рекомендации по созданию слоев пользовательского интерфейса можно найти здесь .
Уровень данных должен предоставлять данные приложения с помощью репозитория.

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

  • Базы данных, хранилище данных, SharedPreferences, API Firebase.
  • Поставщики местоположения GPS.
  • Поставщики данных Bluetooth.
  • Поставщик статуса сетевого подключения.
Используйте сопрограммы и потоки . Используйте сопрограммы и потоки для взаимодействия между уровнями.

Больше лучших практик сопрограмм здесь .

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

Уровень пользовательского интерфейса

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

Рекомендация Описание
Следуйте однонаправленному потоку данных (UDF) . Следуйте принципам однонаправленного потока данных (UDF) , согласно которым модели представления предоставляют состояние пользовательского интерфейса с помощью шаблона наблюдателя и получают действия от пользовательского интерфейса посредством вызовов методов.
Используйте AAC ViewModels, если их преимущества применимы к вашему приложению. Используйте AAC ViewModels для обработки бизнес-логики и получения данных приложения, чтобы представить состояние пользовательского интерфейса в пользовательском интерфейсе (Compose или представления Android).

Дополнительные рекомендации по ViewModel см. здесь.

Ознакомьтесь с преимуществами ViewModels здесь.

Используйте коллекцию состояний пользовательского интерфейса с учетом жизненного цикла. Соберите состояние пользовательского интерфейса из пользовательского интерфейса с помощью соответствующего построителя сопрограмм, учитывающего жизненный цикл: repeatOnLifecycle в системе View и collectAsStateWithLifecycle в Jetpack Compose.

Узнайте больше о repeatOnLifecycle .

Узнайте больше о collectAsStateWithLifecycle .

Не отправляйте события из ViewModel в пользовательский интерфейс. Немедленно обработайте событие в ViewModel и вызовите обновление состояния с результатом обработки события. Подробнее о событиях пользовательского интерфейса здесь .
Используйте приложение с одним действием. Используйте фрагменты навигации или компоновку навигации для навигации между экранами и создания глубоких ссылок на ваше приложение, если ваше приложение имеет более одного экрана.
Используйте Jetpack Compose . Используйте Jetpack Compose для создания новых приложений для телефонов, планшетов, складных устройств и Wear OS.

В следующем фрагменте показано, как собирать состояние пользовательского интерфейса с учетом жизненного цикла:

Просмотры

class MyFragment : Fragment() {

    private val viewModel: MyViewModel by viewModel()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Process item
                }
            }
        }
    }
}

Сочинить

@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}

ViewModel

Модели представления отвечают за предоставление состояния пользовательского интерфейса и доступ к уровню данных. Вот несколько лучших практик для ViewModels:

Рекомендация Описание
Модели ViewModels не должны зависеть от жизненного цикла Android. Модели ViewModels не должны содержать ссылки на какой-либо тип, связанный с жизненным циклом. Не передавайте Activity, Fragment, Context или Resources в качестве зависимости. Если чему-то нужен Context в ViewModel, вам следует тщательно оценить, находится ли он на правильном уровне.
Используйте сопрограммы и потоки .

ViewModel взаимодействует со слоями данных или домена, используя:

  • Kotlin потоки для получения данных приложения,
  • suspend функции для выполнения действий с использованием viewModelScope .
Используйте ViewModels на уровне экрана.

Не используйте ViewModels в повторно используемых частях пользовательского интерфейса. Вы должны использовать ViewModels в:

  • Компонуемые элементы на уровне экрана,
  • Действия/фрагменты в представлениях,
  • Пункты назначения или графики при использовании Jetpack Navigation .
Используйте классы-держатели простого состояния в повторно используемых компонентах пользовательского интерфейса. Используйте классы-держатели простого состояния для решения сложных задач в повторно используемых компонентах пользовательского интерфейса. Поступая таким образом, государство можно поднять и контролировать извне.
Не используйте AndroidViewModel . Используйте класс ViewModel , а не AndroidViewModel . Класс Application не следует использовать в ViewModel. Вместо этого переместите зависимость в пользовательский интерфейс или на уровень данных.
Раскройте состояние пользовательского интерфейса. Модели ViewModels должны предоставлять данные пользовательскому интерфейсу через одно свойство, называемое uiState . Если пользовательский интерфейс отображает несколько несвязанных фрагментов данных, виртуальная машина может предоставить несколько свойств состояния пользовательского интерфейса .
  • Вы должны сделать uiState StateFlow .
  • Вам следует создать uiState с помощью оператора stateIn с политикой WhileSubscribed(5000) (пример) , если данные поступают в виде потока данных из других уровней иерархии.
  • В более простых случаях, когда нет потоков данных, поступающих с уровня данных, допустимо использовать MutableStateFlow представленный как неизменяемый StateFlow (пример) .
  • Вы можете выбрать ${Screen}UiState как класс данных, который может содержать данные, ошибки и сигналы загрузки. Этот класс также может быть запечатанным классом, если разные состояния являются исключительными.

В следующем фрагменте показано, как предоставить состояние пользовательского интерфейса из ViewModel:

@HiltViewModel
class BookmarksViewModel @Inject constructor(
    newsRepository: NewsRepository
) : ViewModel() {

    val feedState: StateFlow<NewsFeedUiState> =
        newsRepository
            .getNewsResourcesStream()
            .mapToFeedState(savedNewsResourcesState)
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5_000),
                initialValue = NewsFeedUiState.Loading
            )

    // ...
}

Жизненный цикл

Ниже приведены некоторые рекомендации по работе с жизненным циклом Android :

Рекомендация Описание
Не переопределяйте методы жизненного цикла в действиях или фрагментах. Не переопределяйте методы жизненного цикла, такие как onResume в действиях или фрагментах. Вместо этого используйте LifecycleObserver . Если приложению необходимо выполнить работу, когда жизненный цикл достигает определенного Lifecycle.State , используйте API repeatOnLifecycle .

В следующем фрагменте показано, как выполнять операции в определенном состоянии жизненного цикла:

Просмотры

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                // ...
            }
            override fun onPause(owner: LifecycleOwner) {
                // ...
            }
        }
    }
}

Сочинить

@Composable
fun MyApp() {

    val lifecycleOwner = LocalLifecycleOwner.current
    DisposableEffect(lifecycleOwner, ...) {
        val lifecycleObserver = object : DefaultLifecycleObserver {
            override fun onStop(owner: LifecycleOwner) {
                // ...
            }
        }

        lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
        }
    }
}

Обработка зависимостей

Существует несколько рекомендаций, которые следует соблюдать при управлении зависимостями между компонентами:

Рекомендация Описание
Используйте внедрение зависимостей . Используйте лучшие практики внедрения зависимостей , в основном внедрение конструктора, когда это возможно.
При необходимости перейдите к компоненту. Область действия — контейнер зависимостей , если тип содержит изменяемые данные, которые необходимо совместно использовать, или тип требует больших затрат на инициализацию и широко используется в приложении.
Используйте Хилт . Используйте Hilt или ручное внедрение зависимостей в простых приложениях. Используйте Hilt , если ваш проект достаточно сложен. Например, если у вас есть:
  • Несколько экранов с ViewModels — интеграция
  • Использование WorkManager — интеграция
  • Расширенное использование навигации, например ViewModels, привязанных к навигационному графу, — интеграция.

Тестирование

Ниже приведены некоторые рекомендации по тестированию :

Рекомендация Описание
Знайте, что тестировать .

Если проект не такой же простой, как приложение hello world, вам следует протестировать его, как минимум, с помощью:

  • Модульное тестирование моделей представлений, включая потоки.
  • Объекты уровня данных модульного теста. То есть репозитории и источники данных.
  • Тесты навигации пользовательского интерфейса, полезные в качестве регрессионных тестов в CI.
Предпочитайте подделки издевательствам. Подробнее читайте в разделе «Использование тестовых двойников» в документации Android .
Тестирование StateFlows. При тестировании StateFlow :

Для получения дополнительной информации ознакомьтесь с руководством «Что тестировать в Android DAC» .

Модели

Вам следует соблюдать следующие рекомендации при разработке моделей в ваших приложениях:

Рекомендация Описание
Создавайте модели для каждого слоя в сложных приложениях.

В сложных приложениях создавайте новые модели в разных слоях или компонентах, когда это имеет смысл. Рассмотрим следующие примеры:

  • Удаленный источник данных может сопоставить модель, которую он получает по сети, с более простым классом, содержащим только те данные, которые нужны приложению.
  • Репозитории могут сопоставлять модели DAO с более простыми классами данных, используя только ту информацию, которая необходима уровню пользовательского интерфейса.
  • ViewModel может включать модели уровня данных в классы UiState .

Соглашения об именах

При присвоении имени вашей кодовой базе вы должны учитывать следующие рекомендации:

Рекомендация Описание
Методы именования.
Необязательный
Методы должны быть глагольной группой. Например, makePayment() .
Именование свойств.
Необязательный
Свойства должны быть существительными. Например, inProgressTopicSelection .
Именование потоков данных.
Необязательный
Когда класс предоставляет поток Flow, LiveData или любой другой поток, соглашение об именах — get{model}Stream() . Например, getAuthorStream(): Flow<Author> Если функция возвращает список моделей, имя модели должно быть во множественном числе: getAuthorsStream(): Flow<List<Author>>
Именование реализаций интерфейсов.
Необязательный
Имена реализаций интерфейсов должны быть осмысленными. Используйте префикс Default , если лучшее имя не найдено. Например, для интерфейса NewsRepository у вас может быть OfflineFirstNewsRepository или InMemoryNewsRepository . Если вы не можете найти хорошее имя, используйте DefaultNewsRepository . Поддельные реализации должны иметь префикс Fake , как в FakeAuthorsRepository .
,

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

Рекомендации ниже сгруппированы по темам. У каждого есть приоритет, который отражает, насколько сильно его рекомендует команда. Список приоритетов выглядит следующим образом:

  • Настоятельно рекомендуется: вам следует применять эту практику, если она не противоречит фундаментальному вашему подходу.
  • Рекомендуется: эта практика может улучшить ваше приложение.
  • Необязательно: эта практика может улучшить ваше приложение в определенных обстоятельствах.

Многоуровневая архитектура

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

Рекомендация Описание
Используйте четко определенный уровень данных . Уровень данных предоставляет данные приложения остальной части приложения и содержит большую часть бизнес-логики вашего приложения.
  • Вам следует создавать репозитории , даже если они содержат только один источник данных.
  • В небольших приложениях вы можете разместить типы слоев данных в пакете data или модуле.
Используйте четко определенный уровень пользовательского интерфейса . Уровень пользовательского интерфейса отображает данные приложения на экране и служит основной точкой взаимодействия с пользователем.
  • В небольших приложениях вы можете разместить типы слоев данных в пакете или модуле ui .
Дополнительные рекомендации по созданию слоев пользовательского интерфейса можно найти здесь .
Уровень данных должен предоставлять данные приложения с помощью репозитория.

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

  • Базы данных, хранилище данных, SharedPreferences, API Firebase.
  • Поставщики местоположения GPS.
  • Поставщики данных Bluetooth.
  • Поставщик статуса сетевого подключения.
Используйте сопрограммы и потоки . Используйте сопрограммы и потоки для взаимодействия между уровнями.

Больше лучших практик сопрограмм здесь .

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

Уровень пользовательского интерфейса

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

Рекомендация Описание
Следуйте однонаправленному потоку данных (UDF) . Следуйте принципам однонаправленного потока данных (UDF) , согласно которым модели представления предоставляют состояние пользовательского интерфейса с помощью шаблона наблюдателя и получают действия от пользовательского интерфейса посредством вызовов методов.
Используйте AAC ViewModels, если их преимущества применимы к вашему приложению. Используйте AAC ViewModels для обработки бизнес-логики и получения данных приложения, чтобы представить состояние пользовательского интерфейса в пользовательском интерфейсе (Compose или представления Android).

Смотрите больше лучших практик ViewModel здесь.

Смотрите преимущества ViewModels здесь.

Используйте коллекцию State Collection Lifecycle. collectAsStateWithLifecycle состояние пользовательского интерфейса из пользовательского интерфейса, используя подходящее строитель repeatOnLifecycle учетом жизненного цикла.

Узнайте больше о repeatOnLifecycle .

Узнайте больше о collectAsStateWithLifecycle .

Не отправляйте события из ViewModel в пользовательский интерфейс. Обработайте событие немедленно в ViewModel и приведите обновление состояния с результатом обработки события. Подробнее о событиях пользовательского интерфейса здесь .
Используйте приложение для одной активности. Используйте навигационные фрагменты или навигацию , чтобы навигацию между экранами и глубокой ссылкой на ваше приложение, если в вашем приложении есть более одного экрана.
Используйте JetPack Compose . Используйте JetPack Compose для создания новых приложений для телефонов, планшетов и складных и износ ОС.

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

Просмотры

class MyFragment : Fragment() {

    private val viewModel: MyViewModel by viewModel()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Process item
                }
            }
        }
    }
}

Сочинить

@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}

ViewModel

ViewModels отвечают за предоставление состояния пользовательского интерфейса и доступ к уровню данных. Вот несколько лучших практик для ViewModels:

Рекомендация Описание
ViewModels должен быть агностиком жизненного цикла Android. ViewModels не должна составлять ссылку на какой-либо тип жизненного цикла. Не проходите Activity, Fragment, Context или Resources как зависимость. Если что -то нуждается Context в ViewModel, вам следует решительно оценить, находится ли это в правильном слое.
Используйте Coroutines и потоки .

ViewModel взаимодействует с слоями данных или домена, используя:

  • Котлин течет для получения данных приложения,
  • suspend функции для выполнения действий, используя viewModelScope .
Используйте ViewModels на уровне экрана.

Не используйте ViewModels в многоразовых частях пользовательского интерфейса. Вы должны использовать ViewModels в:

Используйте классы владельцев простых государств в компонентах повторного использования пользовательского интерфейса. Используйте классы держателя простых государств для обработки сложности в компонентах повторного использования. Делая это, государство можно поднять и контролировать снаружи.
Не используйте AndroidViewModel . Используйте класс ViewModel , а не AndroidViewModel . Класс Application не должен использоваться в ViewModel. Вместо этого переместите зависимость в пользовательском интерфейсе или уровне данных.
Разоблачить состояние пользовательского интерфейса. ViewModels должен разоблачить данные в пользовательском интерфейсе через одно свойство, называемое uiState . Если пользовательский интерфейс показывает несколько неродственных деталей данных, виртуальная машина может выявлять множество свойств состояния пользовательского интерфейса .
  • Вы должны сделать uiState StateFlow .
  • Вы должны создать uiState используя оператор stateIn с помощью политики WhileSubscribed(5000) (пример) (пример) , если данные поступают как поток данных из других слоев иерархии.
  • Для более простых случаев без потоков данных, поступающих из уровня данных, приемлемо использовать MutableStateFlow выявленное в качестве неизменного StateFlow (пример) .
  • Вы можете выбрать ${Screen}UiState в качестве класса данных, который может содержать данные, ошибки и загрузки сигналов. Этот класс также может быть герметичным классом, если различные состояния являются эксклюзивными.

В следующем фрагменте описывается, как разоблачить состояние пользовательского интерфейса из ViewModel:

@HiltViewModel
class BookmarksViewModel @Inject constructor(
    newsRepository: NewsRepository
) : ViewModel() {

    val feedState: StateFlow<NewsFeedUiState> =
        newsRepository
            .getNewsResourcesStream()
            .mapToFeedState(savedNewsResourcesState)
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5_000),
                initialValue = NewsFeedUiState.Loading
            )

    // ...
}

Жизненный цикл

Ниже приведены некоторые лучшие практики для работы с жизненным циклом Android :

Рекомендация Описание
Не переопределяйте методы жизненного цикла в действиях или фрагментах. Не переопределяйте методы жизненного цикла, такие как onResume в действиях или фрагментах. Вместо этого используйте LifecycleObserver . Если приложение нужно выполнять работу, когда жизненный цикл достигает определенного repeatOnLifecycle Lifecycle.State .

Следующий фрагмент описывает, как выполнять операции, учитывая определенное состояние жизненного цикла:

Просмотры

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                // ...
            }
            override fun onPause(owner: LifecycleOwner) {
                // ...
            }
        }
    }
}

Сочинить

@Composable
fun MyApp() {

    val lifecycleOwner = LocalLifecycleOwner.current
    DisposableEffect(lifecycleOwner, ...) {
        val lifecycleObserver = object : DefaultLifecycleObserver {
            override fun onStop(owner: LifecycleOwner) {
                // ...
            }
        }

        lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
        }
    }
}

Обрабатывать зависимости

Есть несколько лучших практик, которые вы должны соблюдать при управлении зависимостями между компонентами:

Рекомендация Описание
Используйте инъекцию зависимости . Используйте наилучшие практики впрыска зависимостей , в основном , когда это возможно.
Прицел в компонент при необходимости. Применение контейнера в зависимости , когда тип содержит изменяемые данные, которые необходимо обмениваться, или тип дороги для инициализации и широко используются в приложении.
Используйте рукоять . Используйте инъекцию вручную или ручную зависимость в простых приложениях. Используйте рукоять, если ваш проект достаточно сложный. Например, если у вас есть:
  • Несколько экранов с ViewModels - винтеграция
  • Использование Workmanager - интеграция
  • Предварительное использование навигации, такого как ViewModels, приведенные к графику NAV - Integration.

Тестирование

Ниже приведены некоторые лучшие практики для тестирования :

Рекомендация Описание
Знать, что тестировать .

Если проект не так прост, как приложение Hello World, вам следует проверить его, как минимум с:

  • Модельные тестовые просмотры, включая потоки.
  • Условия данных модульного теста. То есть репозитории и источники данных.
  • Навигационные тесты пользовательского интерфейса, которые полезны в качестве регрессионных тестов в CI.
Предпочитаю подделки издеваться. Узнайте больше в использовании тестовых удвоений в документации Android .
Тестируйте Stateflows. При тестировании StateFlow :

Для получения дополнительной информации проверьте , что тестировать в руководстве Android DAC .

Модели

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

Рекомендация Описание
Создайте модель на уровень в сложных приложениях.

В сложных приложениях создайте новые модели в разных слоях или компонентах, когда это имеет смысл. Рассмотрим следующие примеры:

  • Удаленный источник данных может составить на карту модель, которую она получает через сеть с более простым классом, только с данными, которые требуются приложения
  • Репозитории могут отображать модели DAO с более простыми классами данных с помощью информации, которую нуждается в уровне пользовательского интерфейса.
  • ViewModel может включать модели слоев данных в классах UiState .

Наименование соглашений

При названии вашей кодовой базы вы должны знать о следующих лучших практиках:

Рекомендация Описание
Методы именования.
Необязательный
Методы должны быть глагольной фразой. Например, makePayment() .
Наименование свойств.
Необязательный
Свойства должны быть существительной фразой. Например, inProgressTopicSelection .
Потоки именования данных.
Необязательный
Когда класс раскрывает поток потока, Livedata или любой другой поток, соглашение о именовании - get{model}Stream() . Например, getAuthorStream(): Flow<Author> Если функция возвращает список моделей, имя модели должно быть во множественном числе: getAuthorsStream(): Flow<List<Author>>
Именование реализаций интерфейсов.
Необязательный
Названия для реализаций интерфейсов должны быть значимыми. Иметь Default в качестве префикса, если лучшее имя не может быть найдено. Например, для интерфейса NewsRepository , вы можете иметь OfflineFirstNewsRepository или InMemoryNewsRepository . Если вы не можете найти хорошего имени, то используйте DefaultNewsRepository . Поддельные реализации должны быть предварительно профиксированы с Fake , как в FakeAuthorsRepository .