Recommandations pour l'architecture Android (vues)

Concepts et implémentation de Jetpack Compose

Cette page présente plusieurs bonnes pratiques et recommandations concernant l'architecture. Adoptez-les pour améliorer la qualité, la robustesse et l'évolutivité de votre application. Elles facilitent également la gestion et le test de votre application.

Couche d'interface utilisateur

Le rôle de la couche d'interface utilisateur est d'afficher les données de l'application à l'écran et de servir de point principal d'interaction utilisateur. Voici quelques bonnes pratiques pour la couche d'interface utilisateur :

  • Créez des dépôts même s'ils ne contiennent qu'une seule source de données.
  • Dans les petites applications, vous pouvez choisir de placer les types de couches de données dans un module ou un package data.

Recommandation

Description

Suivez les principes du flux de données unidirectionnel (UDF).

Fortement recommandé

Suivez les principes du flux de données unidirectionnel (UDF), selon lesquels les ViewModels exposent l'état de l'UI à l'aide du modèle d'observateur et reçoivent les actions de l'UI via des appels de méthode.

Utilisez des ViewModels AAC si cela peut être utile pour votre application.

Fortement recommandé

Utilisez des ViewModels AAC pour gérer la logique métier et récupérer les données de l'application pour exposer l'état de l'UI à l'UI.

En savoir plus sur les bonnes pratiques des ViewModels

En savoir plus sur les avantages des ViewModels

Collectez l'état de l'UI en tenant compte du cycle de vie.

Fortement recommandé

Collectez l'état de l'UI depuis celle-ci à l'aide du compilateur de coroutines qui tient compte du cycle de vie, repeatOnLifecycle.

En savoir plus sur repeatOnLifecycle

N'envoyez pas d'événements du ViewModel à l'UI.

Fortement recommandé

Traitez l'événement immédiatement dans ViewModel et mettez à jour l'état avec le résultat de la gestion de l'événement. En savoir plus sur les événements d'interface utilisateur

Utilisez une application à activité unique.

Recommandé

Utilisez Navigation Fragments pour naviguer entre les écrans, et utilisez des liens profonds vers votre application si elle comporte plusieurs écrans.

L'extrait de code suivant montre comment collecter l'état de l'interface utilisateur en tenant compte du cycle de vie :

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

Les ViewModels fournissent l'état de l'interface utilisateur et l'accès à la couche de données. Voici quelques bonnes pratiques pour les ViewModels :

Recommandation

Description

Les ViewModels doivent être indépendants du cycle de vie d'Android.

Fortement recommandé

Les ViewModels ne doivent faire référence à aucun type lié au cycle de vie. Ne transmettez pas d'Activity, Fragment, Context ni Resources en tant que dépendance. Si un élément a besoin d'un Context dans le ViewModel, vous devez sérieusement vous demander s'il se trouve dans la bonne couche.

Utilisez des coroutines et des flux.

Fortement recommandé

Le ViewModel interagit avec les couches de données ou de domaine à l'aide des éléments suivants :

  • Les flux Kotlin, pour recevoir des données d'application
  • Les fonctions suspend, pour effectuer des actions avec viewModelScope

Utilisez les ViewModels au niveau de l'écran.

Fortement recommandé

N'utilisez pas de ViewModels dans les éléments réutilisables de l'UI. Vous devez utiliser les ViewModels dans les éléments suivants :

  • Activités/Fragments dans Views
  • Destinations ou graphiques lorsque vous utilisez Jetpack Navigation

N'utilisez pas AndroidViewModel.

Fortement recommandé

Utilisez la classe ViewModel, pas AndroidViewModel. La classe Application ne doit pas être utilisée dans le ViewModel. Déplacez plutôt la dépendance vers l'UI ou la couche de données.

Exposez un état de l'interface utilisateur.

Recommandé

Les ViewModels doivent exposer les données à l'UI via une seule propriété appelée uiState. Si l'UI affiche plusieurs données sans liens entre elles, le ViewModel peut exposer plusieurs propriétés d'état de l'UI.

  • Vous devez définir uiState comme StateFlow.
  • Vous devez créer l'uiState à l'aide de l'opérateur stateIn avec la règle WhileSubscribed(5000) (exemple) si les données arrivent sous la forme d'un flux de données provenant d'autres couches de la hiérarchie.
  • Dans les cas plus simples où aucun flux de données ne provient de la couche de données, il est possible d'utiliser un MutableStateFlow exposé en tant que StateFlow immuable.
  • Vous pouvez choisir d'utiliser ${Screen}UiState comme classe de données pouvant contenir des données, des erreurs et des signaux de chargement. Cette classe peut également être scellée si les différents états sont exclusifs.

L'extrait de code suivant montre comment exposer l'état de l'interface utilisateur à partir d'un 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
            )

    // ...
}

Cycle de vie

Voici quelques bonnes pratiques pour le cycle de vie Android :

Recommandation

Description

N'ignorez pas les méthodes du cycle de vie dans les activités ou les fragments.

Fortement recommandé

N'ignorez pas les méthodes du cycle de vie comme onResume dans les activités ou les fragments. Utilisez LifecycleObserver à la place. Si l'application doit effectuer des tâches lorsque le cycle de vie atteint un certain Lifecycle.State, utilisez l'API repeatOnLifecycle.

L'extrait de code suivant montre comment effectuer des opérations en fonction d'un certain état du cycle de vie :

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) {
                // ...
            }
        }
    }
}