Рекомендации по архитектуре Android (представлениям)

Концепции и реализация Jetpack Compose

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

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

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

  • Вам следует создавать репозитории , даже если они содержат только один источник данных.
  • В небольших приложениях вы можете размещать типы слоев данных в пакете data или модуле.

Рекомендация

Описание

Следуйте однонаправленному потоку данных (UDF) .

Настоятельно рекомендуется

Следуйте принципам однонаправленного потока данных (UDF) , где ViewModels предоставляют доступ к состоянию пользовательского интерфейса, используя шаблон наблюдателя, и получают действия от пользовательского интерфейса посредством вызовов методов.

Используйте AAC ViewModels, если их преимущества применимы к вашему приложению.

Настоятельно рекомендуется

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

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

О преимуществах ViewModel можно узнать здесь .

Используйте сбор состояний пользовательского интерфейса с учетом жизненного цикла.

Настоятельно рекомендуется

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

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

Не отправляйте события из ViewModel в пользовательский интерфейс.

Настоятельно рекомендуется

Обработайте событие немедленно в ViewModel и вызовите обновление состояния с результатом обработки события. Подробнее о событиях пользовательского интерфейса здесь .

Используйте приложение, предназначенное для выполнения одной задачи.

Рекомендуется

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

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

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
                }
            }
        }
    }
}

ViewModel

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

Рекомендация

Описание

ViewModels должны быть независимы от жизненного цикла Android.

Настоятельно рекомендуется

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

Используйте сопрограммы и потоки выполнения .

Настоятельно рекомендуется

Модель представления взаимодействует с уровнями данных или предметной области с помощью следующих методов:

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

Используйте ViewModel на уровне экрана.

Настоятельно рекомендуется

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

  • Действия/фрагменты в представлениях
  • Пункты назначения или графики при использовании Jetpack Navigation .

Не используйте AndroidViewModel .

Настоятельно рекомендуется

Используйте класс ViewModel , а не AndroidViewModel . Класс Application не следует использовать в ViewModel. Вместо этого перенесите зависимость в пользовательский интерфейс или слой данных.

Предоставьте доступ к состоянию пользовательского интерфейса.

Рекомендуется

ViewModels должны предоставлять данные пользовательскому интерфейсу через одно свойство, называемое uiState . Если пользовательский интерфейс отображает несколько несвязанных между собой элементов данных, ViewModel может предоставлять несколько свойств состояния пользовательского интерфейса .

  • Вам следует преобразовать 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 :

Рекомендация

Описание

Не следует переопределять методы жизненного цикла в Activity или Frags.

Настоятельно рекомендуется

Не переопределяйте методы жизненного цикла, такие как onResume в Activity или Fragment. Вместо этого используйте 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) {
                // ...
            }
        }
    }
}