Intégration d'activités

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

L'intégration d'activités permet d'optimiser une application pour les grands écrans en divisant sa fenêtre de tâches en deux activités ou deux instances d'une même activité.

Figure 1. Application Paramètres affichant des activités côte à côte.

La mise à jour des anciens codebases pour les grands écrans demande beaucoup de temps et de travail. Par ailleurs, la conversion d'applications basées sur des activités en mises en page à plusieurs volets à l'aide de fragments implique d'importants efforts de refactorisation.

L'intégration d'activités nécessite peu ou pas de refactorisation de votre appli. Il vous suffit de créer un fichier de configuration XML ou d'effectuer des appels d'API Jetpack WindowManager pour déterminer la manière dont votre application affichera ses activités (côte à côte ou empilées les unes sur les autres).

Les petits écrans sont gérés automatiquement. Lorsque votre application est installée sur un appareil doté d'un petit écran, les activités sont empilées les unes au-dessus des autres. Sur les grands écrans, les activités sont affichées côte à côte. Le système détermine la présentation en fonction de la configuration que vous avez créée. Aucune logique de branche n'est nécessaire.

L'intégration d'activités est compatible avec les changements d'orientation des appareils et fonctionne parfaitement sur les pliables, qui empilent et dépilent les activités lorsque l'appareil se plie et se déplie.

Le développement Android moderne utilise une architecture à activité unique avec des fragments, des composants de navigation et des gestionnaires de mise en page polyvalents comme SlidingPaneLayout.

Toutefois, si votre application se compose de plusieurs activités, l'intégration d'activités vous permet de proposer facilement une expérience utilisateur améliorée sur les tablettes, les pliables et les appareils Chrome OS.

L'intégration d'activités est prise en charge sur Android 12L (niveau d'API 32) ou version ultérieure.

Fractionner la fenêtre de tâches

L'intégration d'activités divise la fenêtre de tâches de l'application en deux conteneurs : un conteneur principal et un conteneur secondaire. Ils hébergent les activités lancées à partir de l'activité principale ou d'autres activités qui se trouvent déjà dans les conteneurs.

Les activités sont empilées dans le conteneur secondaire au fur et à mesure de leur lancement. Sur les petits écrans, ce conteneur est également empilé sur le conteneur principal. Dans ce cas, l'empilement des activités et la navigation arrière sont cohérents avec l'ordre des activités déjà intégrées dans l'application.

L'intégration d'activités vous permet d'afficher les activités de différentes manières. Votre application peut lancer deux activités côte à côte et fractionner ainsi la fenêtre de tâches :

Figure 2. Deux activités côte à côte

De même, une activité qui occupe la totalité de la fenêtre de tâches peut également lancer une nouvelle activité en parallèle et fractionner l'écran :

Figure 3. L'activité A lance l'activité B à côté

Les activités partageant une fenêtre de tâches et qui sont déjà sur un écran fractionné peuvent lancer d'autres activités de différentes manières :

  • Sur le côté en haut d'une autre activité :

    Figure 4. L'activité A ouvre l'activité C sur le côté, au-dessus de l'activité B
  • Sur le côté, en déplaçant horizontalement l'écran fractionné et en masquant ainsi l'activité principale précédente :

    Figure 5. L'activité B lance l'activité C sur le côté et déplace l'écran fractionné horizontalement
  • La nouvelle activité lancée remplace l'activité lancée précédemment dans la même pile d'activités :

    Figure 6. L'activité B lance l'activité C sans indicateur d'intent supplémentaire
  • L'activité lancée s'affiche dans toute la fenêtre dans la même tâche :

    Figure 7. L'activité A ou B déclenche l'activité C, qui remplit la fenêtre de tâches

Navigation arrière

Différents types d'applications peuvent avoir des règles de navigation arrière différentes lorsque la fenêtre de tâches est fractionnée. Ces règles varient en fonction des dépendances entre les activités ou de la manière dont les utilisateurs déclenchent l'événement "Retour". Voici quelques exemples :

  • Fermeture simultanée des activités : si les activités sont liées et ne peuvent pas s'afficher sans l'autre, la navigation arrière peut être configurée pour les fermer toutes les deux.
  • Fermeture indépendante d'une activité : si les activités sont totalement indépendantes, la navigation arrière au niveau d'une activité n'affecte pas l'état d'une autre activité dans la fenêtre de tâches.

Si vous utilisez un bouton, l'événement "Retour" est envoyé à la dernière activité sélectionnée. Si vous utilisez un geste tactile, l'événement "Retour" est envoyé à l'activité où le geste a eu lieu.

Mise en page à plusieurs volets

Jetpack WindowManager 1.1.0 Alpha04 vous permet de créer une mise en page à plusieurs volets sur les appareils à grand écran compatibles avec la version 12L (niveau d'API 32) et sur certains appareils dotés d'une version antérieure de la plate-forme. Les applications existantes qui sont basées sur plusieurs activités plutôt que sur des fragments ou des mises en page basées sur les vues, comme SlidingPaneLayout, peuvent proposer une meilleure expérience utilisateur sur les grands écrans sans nécessiter d'importants efforts de refactorisation.

Le fractionnement "liste/détail" est un exemple courant. Pour garantir une présentation de qualité, le système lance l'activité "Liste", puis l'application lance immédiatement l'activité "Détail". Le système de transition attend que les deux activités soient dessinées, puis les affiche ensemble. Pour l'utilisateur, ces deux activités sont lancées comme s'il n'y en avait qu'une seule.

Figure 8. Deux activités ont été lancées simultanément dans une mise en page à plusieurs volets

Proportions du fractionnement

Votre application peut spécifier la façon dont la fenêtre de tâches est proportionnée par l'attribut ratio d'une configuration de fractionnement (consultez la section Configuration de fractionnement ci-dessous).

Figure 9. Deux fractionnements d'activités avec différentes proportions

Espaces réservés

Les activités d'un espace réservé sont des activités secondaires vides qui occupent un espace spécifique dans un fractionnement d'activité. Ils sont destinés à être remplacés par une autre activité comprenant du contenu. Par exemple, l'activité d'un espace réservé peut occuper le conteneur secondaire d'un fractionnement d'activité dans une mise en page Liste/Détail. Dans ce cas, lorsqu'un élément de la liste est sélectionné, une activité contenant les informations détaillées correspondant à cet élément remplace l'espace réservé.

Les espaces réservés ne s'affichent que si l'espace disponible est suffisant pour un fractionnement. Ils sont automatiquement éliminés lorsque la taille de l'écran passe à une largeur trop petite pour afficher un fractionnement d'activité, mais ils sont relancés automatiquement (avec un état réinitialisé) lorsque l'espace le permet.

Figure 10. Appareil pliable qui se plie et se déplie. L'activité de l'espace réservé est éliminée, puis relancée lorsque la taille de l'écran change.

Changements de taille de la fenêtre

Lorsque les changements de configuration de l'appareil réduisent la largeur de la fenêtre de tâches et qu'elle n'est plus assez grande pour une mise en page à plusieurs volets (par exemple, lorsqu'un appareil pliable à grand écran passe du format "tablette" au format "téléphone" ou lorsque la fenêtre de l'application passe en mode multifenêtre), les activités de l'espace réservé dans le volet secondaire de la fenêtre de tâches sont superposées aux activités du volet principal.

Les activités d'un espace réservé ne s'affichent que lorsque la largeur de l'écran est suffisante pour le fractionnement. Sur les petits écrans, l'espace réservé est automatiquement fermé. Lorsque la zone d'affichage redevient suffisamment grande, l'espace réservé est recréé (voir la section Espaces réservés ci-dessus).

L'empilement d'activités est possible, car WindowManager classe les activités dans le volet secondaire au-dessus des activités du volet principal.

Plusieurs activités dans le volet secondaire

L'activité B lance l'activité C sans indicateur d'intent supplémentaire :

Fractionnement contenant les activités A, B et C, avec C empilé sur B.

Les activités sont classées dans cet ordre dans la même tâche :

Pile secondaire contenant l'activité C superposée à B
          La pile secondaire est empilée sur la pile d'activité principale contenant l'activité A.

Par conséquent, dans une fenêtre de tâches de petite taille, l'application se limite à une seule activité et positionne C en haut de la pile :

Fenêtre de petite taille n'affichant que l'activité C.

La navigation arrière dans la fenêtre de petite taille vous permet de parcourir les activités empilées les unes sur les autres.

Si la taille de la fenêtre de tâches est agrandie de sorte à pouvoir accueillir plusieurs volets, les activités s'affichent à nouveau côte à côte.

Fractionnements empilés

L'activité B lance l'activité C sur le côté et déplace l'écran fractionné horizontalement :

Fenêtre de tâches montrant les activités A et B, puis les activités B et C.

Les activités sont classées dans cet ordre dans la même tâche :

Activités A, B et C dans une seule pile. Les activités sont empilées de haut en bas dans l'ordre suivant : C, B, A.

Dans une fenêtre de tâches de petite taille, l'application se limite à une seule activité et positionne C en haut :

Fenêtre de petite taille n'affichant que l'activité C.

Configuration de fractionnement

La bibliothèque WindowManager permet de créer des conteneurs et des fractionnements en fonction de règles de fractionnement spécifiques. La configuration des règles de fractionnement comprend plusieurs étapes :

  1. Ajoutez la dernière dépendance de la bibliothèque WindowManager à votre fichier build.gradle, par exemple :

    implementation 'androidx.window:window:1.1.0-alpha04'

  2. Créez un fichier de ressources qui remplit les conditions suivantes :

    • Il configure les options de fractionnement pour toutes les activités qui partagent un fractionnement.
    • Il définit les activités à fractionner à l'aide de filtres.
    • Il spécifie les activités à ne jamais fractionner.

    Exemple :

    <!-- main_split_config.xml -->
    
    <!-- The split configuration for activities. -->
    <resources
        xmlns:window="http://schemas.android.com/apk/res-auto">
    
        <!-- Define a split for the named activity pair. -->
        <SplitPairRule
            window:splitRatio="0.3"
            window:splitMinWidth="600dp"
            window:finishPrimaryWithSecondary="never"
            window:finishSecondaryWithPrimary="always">
            <SplitPairFilter
                window:primaryActivityName=".SplitActivityList"
                window:secondaryActivityName=".SplitActivityDetail"/>
        </SplitPairRule>
    
        <!-- Automatically launch a placeholder for the list activity. -->
        <SplitPlaceholderRule
            window:placeholderActivityName=".SplitActivityListPlaceholder"
            window:splitRatio="0.3"
            window:splitMinWidth="600dp">
            <ActivityFilter
                window:activityName=".SplitActivityList"/>
        </SplitPlaceholderRule>
    
        <!-- Define activities that should never enter a split. Note: Takes
             precedence over other split rules. -->
        <ActivityRule
            window:alwaysExpand="true">
            <ActivityFilter window:activityName=".FullscreenActivity"/>
        </ActivityRule>
    
    </resources>
    
  3. Informez la bibliothèque sur les définitions des règles.

    Dans cet exemple, nous utilisons la bibliothèque Jetpack Startup pour effectuer l'initialisation avant le chargement des autres composants de l'application et avant le lancement des activités. Pour activer la fonctionnalité de démarrage, ajoutez la dépendance de la bibliothèque dans le fichier de compilation de l'application :

    implementation 'androidx.startup:startup-runtime:1.1.1'

    Puis, ajoutez l'entrée suivante dans le fichier manifeste de l'application :

    <!-- AndroidManifest.xml -->
    
    <provider android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
        <!-- This entry makes ExampleWindowInitializer discoverable. -->
        <meta-data  android:name="androidx.window.sample.embedding.ExampleWindowInitializer"
            android:value="androidx.startup" />
    </provider>
    
  4. Enfin, ajoutez l'implémentation de la classe d'initialisation.

    Pour définir les règles, indiquez à SplitController.initialize() l'ID du fichier de ressources XML qui contient les définitions (main_split_config) :

    Kotlin

    class ExampleWindowInitializer : Initializer<SplitController> {
       override fun create(context: Context): SplitController {
           SplitController.initialize(context, R.xml.main_split_config)
           return SplitController.getInstance(context)
       }
    
       override fun dependencies(): List<Class<out Initializer<*>>> {
           return emptyList()
       }
    }
    

    Java

    class ExampleWindowInitializer extends Initializer<SplitController> {
       @Override
       SplitController create(Context context) {
           SplitController.initialize(context, R.xml.main_split_config);
           return SplitController.getInstance(context);
       }
    
       @Override
       List<Class<? extends Initializer<?>>> dependencies() {
           return emptyList();
       }
    }
    

Exemples de fractionnement

Fractionnement de la fenêtre entière

Figure 11. L'activité A lance l'activité B à côté

Aucune refactorisation n'est nécessaire. Vous pouvez définir la configuration de fractionnement en mode statique ou au moment de l'exécution, puis appeler Context#startActivity() sans aucun paramètre supplémentaire.

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Fractionnement par défaut

Lorsque la page de destination d'une application est conçue pour être fractionnée en deux conteneurs sur les grands écrans, l'expérience utilisateur est optimale lorsque les deux activités sont créées et présentées simultanément. Toutefois, le contenu destiné au conteneur secondaire du fractionnement n'est pas toujours disponible tant que l'utilisateur n'a pas interagi avec l'activité du conteneur principal (tant qu'il n'a pas sélectionné un élément dans un menu de navigation, par exemple). L'activité d'un espace réservé peut combler le vide jusqu'à ce que le contenu puisse être affiché dans le conteneur secondaire du fractionnement (voir la section Espaces réservés ci-dessus).

Figure 12. Fractionnement créé en ouvrant deux activités simultanément. L'une des activités correspond à un espace réservé.

Pour créer un fractionnement avec un espace réservé, créez un espace réservé et associez-le à l'activité principale :

<SplitPlaceholderRule
    window:placeholderIntentName=".Placeholder">
    <ActivityFilter
        window:activityName=".Main"/>
</SplitPlaceholderRule>

Lorsqu'une application reçoit un intent, l'activité cible peut être affichée en tant que partie secondaire d'un fractionnement d'activité (requête d'affichage d'un écran détaillé contenant des informations sur l'élément d'une liste, par exemple). Sur les petits écrans, le détail s'affiche dans la fenêtre de tâches entière. Sur les grands écrans, il s'affiche à côté de la liste.

Figure 13. Activité "Détail" affichée seule sur un petit écran grâce à un lien profond et affichée avec l'activité "Liste" sur un grand écran.

La requête de lancement doit être acheminée vers l'activité principale, et l'activité cible destinée aux détails doit être lancée dans un écran fractionné. SplitController choisit automatiquement la présentation appropriée (empilée ou côte à côte) en fonction de la largeur d'affichage disponible.

Kotlin

override fun onCreate(savedInstanceState Bundle?) {
    …
    splitController.registerRule(SplitPairRule(newFilters))
    startActivity(Intent(this, DetailActivity::class.java))
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    …
    splitController.registerRule(new SplitPairRule(newFilters));
    startActivity(new Intent(this, DetailActivity.class));
}

La destination du lien profond peut être la seule activité disponible pour l'utilisateur dans la pile de navigation arrière, auquel cas il peut être utile de ne pas fermer l'activité "Détail" pour n'afficher que l'activité principale :

Grand écran avec l&#39;activité &quot;Liste&quot; et l&#39;activité &quot;Détail&quot; côte à côte.
          Navigation arrière qui ne parvient pas à ignorer l&#39;activité &quot;Détail&quot; et à laisser l&#39;activité &quot;Liste&quot; à l&#39;écran.

Petit écran n'affichant que l'activité "Détail". Navigation arrière qui ne parvient pas à ignorer l'activité "Détail" et à afficher l'activité "Liste" à l'écran.

À la place, vous pouvez arrêter les deux activités simultanément avec l'attribut finishPrimaryWithSecondary :

<SplitPairRule
    window:finishPrimaryWithSecondary="always">
    <SplitPairFilter
        window:primaryActivityName=".List"
        window:secondaryActivityName=".Detail"/>
</SplitPairRule>

Plusieurs activités dans des conteneurs fractionnés

L'empilement de plusieurs activités dans un conteneur fractionné permet aux utilisateurs d'accéder à un contenu profond. Par exemple, avec un fractionnement Liste/Détail, l'utilisateur doit parfois accéder à une section de sous-détails tout en conservant l'activité principale :

Figure 14. Activité ouverte dans le volet secondaire complet de la fenêtre de tâches.

Kotlin

class DetailActivity {
    …
    fun onOpenSubDetail() {
      startActivity(Intent(this, SubDetailActivity::class.java))
    }
}

Java

public class DetailActivity {
    …
    void onOpenSubDetail() {
        startActivity(new Intent(this, SubDetailActivity.class));
    }
}

L'activité du sous-détail est placée au-dessus de l'activité du détail et la dissimule :

L'utilisateur peut ensuite revenir au niveau de détail précédent via la navigation arrière dans la pile :

Figure 15. Activité supprimée du haut de la pile.

Les activités sont empilées par défaut lorsqu'elles sont lancées à partir d'une activité qui se trouve dans le même conteneur secondaire. Les activités lancées à partir du conteneur principal dans un fractionnement actif se retrouvent également dans le conteneur secondaire, au-dessus de la pile d'activités.

Activités dans une nouvelle tâche

Lorsque des activités d'une fenêtre de tâches fractionnée déclenchent d'autres activités dans une nouvelle tâche, cette dernière est distincte de la tâche qui inclut le fractionnement et s'affiche en plein écran. L'écran "Récents" affiche deux tâches : la tâche sur l'écran fractionné et la nouvelle tâche.

Figure 16. Lancement de l'activité C dans une nouvelle tâche à partir de l'activité B

Remplacement d'activité

Les activités peuvent être remplacées dans la pile du conteneur secondaire (lorsque l'activité principale est utilisée pour la navigation de premier niveau et que l'activité secondaire est une destination sélectionnée, par exemple). Chaque sélection dans la navigation de premier niveau devrait lancer une nouvelle activité dans le conteneur secondaire et supprimer l'activité ou les activités qui s'y trouvaient précédemment.

Figure 17. L'activité de navigation de premier niveau dans le volet principal remplace les activités de destination dans le volet secondaire.

Si l'application ne termine pas l'activité du conteneur secondaire lorsque la sélection change dans la navigation, la navigation arrière peut être source de confusion lorsque le fractionnement est réduit (lorsque l'appareil est plié). Par exemple, si vous avez un menu dans le volet principal et que les écrans A et B sont empilés dans le volet secondaire, lorsque l'utilisateur plie le téléphone, B se trouvera au-dessus de l'écran A, qui se trouvera lui-même au-dessus du menu. Lorsque l'utilisateur effectuera un retour arrière à partir de B, l'écran A apparaîtra au lieu du menu.

Dans ce cas, l'écran A doit être supprimé de la pile "Retour".

Par défaut, le lancement sur le côté dans un nouveau conteneur au-dessus d'un écran déjà fractionné place les nouveaux conteneurs secondaires au-dessus et conserve les anciens dans la pile "Retour". Vous pouvez configurer les fractionnements pour que les conteneurs secondaires précédents soient effacés avec clearTop et lancer normalement les nouvelles activités.

<SplitPairRule
    window:clearTop="true">
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenA"/>
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenB"/>
</SplitPairRule>

Kotlin

class MenuActivity {
    …
    fun onMenuItemSelected(selectedMenuItem: Int) {
        startActivity(Intent(this, classForItem(selectedMenuItem)))
    }
}

Java

public class MenuActivity {
    …
    void onMenuItemSelected(int selectedMenuItem) {
        startActivity(new Intent(this, classForItem(selectedMenuItem)));
    }
}

Vous pouvez également utiliser la même activité secondaire et, à partir de l'activité principale (menu), envoyer de nouveaux intents qui renvoient à la même instance, mais déclenchent une mise à jour de l'état ou de l'interface utilisateur dans le conteneur secondaire.

Fonctionnement de plusieurs écrans fractionnés

Les applications peuvent fournir une navigation profonde à plusieurs niveaux en lançant des activités supplémentaires sur le côté.

Lorsqu'une activité dans un conteneur secondaire lance une nouvelle activité sur le côté, un écran fractionné est créé au-dessus de l'écran fractionné existant.

Figure 18. L'activité B lance l'activité C sur le côté.

La pile "Retour" contient toutes les activités qui ont été ouvertes afin que les utilisateurs puissent accéder à l'écran fractionné A/B une fois qu'ils auront fermé l'écran C.

Activités A, B et C dans une pile. Les activités sont empilées de haut en bas dans l'ordre suivant : C, B, A.

Pour créer un autre écran fractionné, lancez la nouvelle activité sur le côté du conteneur secondaire existant. Déclarez les configurations correspondant aux écrans fractionnés A/B et B/C, puis lancez l'activité C normalement à partir de B :

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
    <SplitPairFilter
        window:primaryActivityName=".B"
        window:secondaryActivityName=".C"/>
</SplitPairRule>

Kotlin

class B {
    fun onOpenC() {
        startActivity(Intent(this, C::class.java))
    }
}

Java

public class B {
    …
    void onOpenC() {
        startActivity(new Intent(this, C.class));
    }
}

Réagir aux changements d'état des écrans fractionnés

Différentes activités d'application peuvent comporter des éléments d'interface utilisateur ayant la même fonction (commande qui ouvre une fenêtre contenant les paramètres du compte, par exemple).

Figure 19. Activités distinctes avec des éléments d'interface utilisateur identiques du point de vue fonctionnel.

Si deux activités qui partagent un élément d'interface utilisateur commun sont fractionnées, il est redondant et parfois déroutant d'afficher cet élément dans les deux activités.

Figure 20. Éléments d'interface utilisateur en double dans les écrans fractionnés d'une activité.

Pour déterminer quand les activités sont dans un écran fractionné, enregistrez un écouteur avec SplitController afin de suivre les changements d'état des écrans fractionnés. Ajustez ensuite l'interface utilisateur en conséquence :

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    splitController
        .addSplitListener(this, mainThreadExecutor, SplitInfoChangeCallback())
}

inner class SplitInfoChangeCallback : Consumer<List<SplitInfo>> {
    override fun accept(splitInfoList: List<SplitInfo>) {
        findViewById<View>(R.id.infoButton).visibility =
            if (!splitInfoList.isEmpty()) View.GONE else View.VISIBLE
    }
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    splitController
        .addSplitListener(this, mainThreadExecutor, SplitInfoChangeCallback());
}

class SplitInfoChangeCallback extends Consumer<List<SplitInfo>> {
    public void accept(List<SplitInfo> splitInfoList) {
        findViewById<View>(R.id.infoButton).visibility =
            !splitInfoList.isEmpty()) ? View.GONE : View.VISIBLE;
    }
}

Les rappels peuvent être effectués à n'importe quel état du cycle de vie, y compris lorsqu'une activité est arrêtée. L'enregistrement des écouteurs doit généralement être activé dans onStart() et être annulé dans onStop().

Fenêtre modale plein écran

Certaines activités empêchent les utilisateurs d'interagir avec l'application tant qu'une action spécifique n'a pas été effectuée (par exemple, un écran d'authentification, un écran de confirmation d'un règlement ou un message d'erreur). Les activités modales ne doivent pas s'afficher dans des écrans fractionnés.

Pour forcer une activité à toujours remplir la fenêtre de tâches, utilisez la configuration d'expansion :

<ActivityRule
    window:alwaysExpand="true">
    <ActivityFilter
        window:activityName=".FullWidthActivity"/>
</ActivityRule>

Arrêter les activités

Les utilisateurs peuvent arrêter les activités de chaque côté de l'écran fractionné en balayant l'écran depuis le bord :

Figure 21. Geste de balayage de l'écran qui met fin à l'activité B.
Figure 22. Geste de balayage de l'écran qui met fin à l'activité A.

Si l'appareil est configuré pour utiliser le bouton "Retour" au lieu de la navigation par gestes, l'entrée est envoyée à l'activité sélectionnée, à savoir celle sur laquelle l'utilisateur a appuyé en dernier ou celle qu'il a lancée en dernier.

L'arrêt de l'une des activités d'un écran fractionné dépend de la configuration du fractionnement.

Configuration par défaut

Lorsqu'une activité de l'écran fractionné est arrêtée, l'activité restante occupe la totalité de la fenêtre :

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Écran fractionné contenant les activités A et B. L'activité A est arrêtée. En conséquence, l'activité B occupe la fenêtre entière.

Écran fractionné contenant les activités A et B. L'activité B est arrêtée. En conséquence, l'activité A occupe la fenêtre entière.

Mettre fin aux activités simultanément

Pour arrêter automatiquement l'activité principale en même temps que l'activité secondaire, utilisez ce code :

<SplitPairRule
    window:finishPrimaryWithSecondary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Écran fractionné contenant les activités A et B. L'activité B est arrêtée, ce qui met également fin à l'activité A, laissant la fenêtre de tâches vide.

Écran fractionné contenant les activités A et B. L'activité A est arrêtée. L'activité B apparaît seule dans la fenêtre de tâches.

Pour arrêter automatiquement l'activité secondaire en même temps que l'activité principale, utilisez ce code :

<SplitPairRule
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Écran fractionné contenant les activités A et B. L'activité A est arrêtée, ce qui met également fin à l'activité B, laissant la fenêtre de tâches vide.

Écran fractionné contenant les activités A et B. L'activité B est arrêtée. L'activité A apparaît seule dans la fenêtre de tâches.

Pour mettre fin aux activités simultanément lorsque l'activité principale ou secondaire est arrêtée, utilisez ce code :

<SplitPairRule
    window:finishPrimaryWithSecondary="always"
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Écran fractionné contenant les activités A et B. L'activité A est arrêtée, ce qui met également fin à l'activité B, laissant la fenêtre de tâches vide.

Écran fractionné contenant les activités A et B. L'activité B est arrêtée, ce qui met également fin à l'activité A, laissant la fenêtre de tâches vide.

Mettre fin à plusieurs activités dans les conteneurs

Si plusieurs activités sont empilées dans un conteneur fractionné, l'arrêt d'une activité au bas de la pile ne met pas automatiquement fin aux activités en haut de la pile.

Par exemple, si deux activités se trouvent dans le conteneur secondaire, C au-dessus de B :

La pile secondaire contenant l'activité C empilée sur B, est empilée sur la pile principale contenant l'activité A.

Et si la configuration du fractionnement est définie par la configuration des activités A et B :

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

L'arrêt de l'activité située en haut de la pile conserve le fractionnement.

Écran fractionné avec l'activité A dans le conteneur principal et les activités B et C dans le conteneur secondaire, avec l'activité C empilée sur B. L'activité C est arrêtée, ce qui laisse A et B dans l'écran fractionné.

L'arrêt de l'activité inférieure (racine) du conteneur secondaire n'entraîne pas la suppression des activités qui se trouvent au-dessus, et conserve donc aussi le fractionnement.

Écran fractionné avec l'activité A dans le conteneur principal et les activités B et C dans le conteneur secondaire, avec l'activité C empilée sur B. L'activité B est arrêtée, ce qui laisse A et C dans l'écran fractionné.

Toute règle supplémentaire permettant de mettre fin aux activités simultanément, telle que l'arrêt de l'activité secondaire en même temps que l'activité principale, est également exécutée :

<SplitPairRule
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Écran fractionné avec l'activité A dans le conteneur principal et les activités B et C dans le conteneur secondaire, avec l'activité C empilée sur B. L'activité A est arrêtée, ce qui met également fin aux activités B et C.

Et lorsque le fractionnement est configuré pour mettre fin à l'activité principale et à l'activité secondaire simultanément :

<SplitPairRule
    window:finishPrimaryWithSecondary="always"
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Écran fractionné avec l'activité A dans le conteneur principal et les activités B et C dans le conteneur secondaire, avec l'activité C empilée sur B. L'activité C est arrêtée, ce qui laisse A et B dans l'écran fractionné.

Écran fractionné avec l'activité A dans le conteneur principal et les activités B et C dans le conteneur secondaire, avec l'activité C empilée sur B. L'activité B est arrêtée, ce qui laisse A et C dans l'écran fractionné.

Écran fractionné avec l'activité A dans le conteneur principal et les activités B et C dans le conteneur secondaire, avec l'activité C empilée sur B. L'activité A est arrêtée, ce qui met également fin aux activités B et C.

Modifier les propriétés de fractionnement au moment de l'exécution

Il n'est pas possible de modifier les propriétés d'un fractionnement actif et visible. La modification des règles de fractionnement s'applique au lancement d'activités supplémentaires et aux nouveaux conteneurs, pas aux fractionnements actifs existants.

Pour modifier les propriétés des fractionnements actifs, arrêtez les activités secondaires dans l'écran fractionné, puis lancez-les de nouveau sur le côté avec une nouvelle configuration.

Extraire une activité d'un écran fractionné pour l'afficher dans la fenêtre complète

Créez une configuration qui affichera l'activité secondaire dans une fenêtre complète, puis relancez cette activité avec un intent qui résout la même instance.

Vérifier la compatibilité du fractionnement au moment de l'exécution

L'intégration d'activités est une fonctionnalité d'Android 12L (niveau d'API 32), mais elle est également disponible sur certains appareils dotés d'une version antérieure de la plate-forme. Pour vérifier la disponibilité de cette fonctionnalité au moment de l'exécution, utilisez la méthode SplitController.isSplitSupported() :

Kotlin

val splitController = SplitController.Companion.getInstance()
if (splitController.isSplitSupported()) {
    // Device supports split activity features.
}

Java

SplitController splitController = SplitController.Companion.getInstance();
if (splitController.isSplitSupported()) {
  // Device supports split activity features.
}

Si les fractionnements ne sont pas pris en charge, les activités sont lancées au-dessus, conformément au modèle d'intégration sans activité.

Empêcher le remplacement du système

Les fabricants d'appareils Android (fabricants d'équipement d'origine, ou OEM) peuvent implémenter l'intégration d'activités en tant que fonction du système de l'appareil. Le système spécifie des règles de fractionnement pour les applications à plusieurs activités, ignorant ainsi leur comportement de fenêtrage. Le remplacement du système force les applications à plusieurs activités à utiliser un mode d'intégration d'activités défini par le système.

L'intégration des activités du système peut améliorer la présentation de l'appli au moyen de mises en page à plusieurs volets, telle que list-detail, sans modifier l'appli. Toutefois, ce type d'intégration peut également donner lieu à des mises en page d'application incorrectes, des bugs ou des conflits avec l'intégration des activités implémentée par l'appli.

Votre appli peut empêcher ou autoriser l'intégration des activités système en définissant une propriété dans son fichier manifeste, par exemple :

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <property
            android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE"
            android:value="true|false" />
    </application>
</manifest>

Le nom de la propriété est défini dans l'objet WindowProperties de Jetpack WindowManager. Définissez la valeur sur false si votre appli implémente l'intégration d'activités ou si vous souhaitez empêcher le système d'appliquer ses règles d'intégration d'activités à votre appli. Définissez la valeur sur true pour autoriser le système à appliquer son intégration d'activités à votre appli.

Limites, restrictions et mises en garde

  • Seule l'application hôte de la tâche, identifiée comme propriétaire de l'activité racine, peut y organiser et y intégrer d'autres activités. Si les activités compatibles avec l'intégration et le fractionnement s'exécutent dans une tâche appartenant à une autre application, ces opérations ne fonctionneront pas.
  • Les activités ne peuvent être organisées que dans une seule tâche. Le lancement d'une activité dans une nouvelle tâche la place toujours dans une nouvelle fenêtre développée en dehors des écrans fractionnés existants.
  • Seules les activités d'un même processus peuvent être organisées et fractionnées. Le rappel SplitInfo ne signale que les activités qui appartiennent au même processus, car il n'existe aucun moyen d'identifier les activités associées à d'autres processus.
  • Chaque règle d'activité unique ou par paire s'applique uniquement aux lancements d'activités qui se produisent après l'enregistrement de la règle. Il n'existe actuellement aucun moyen de mettre à jour les fractionnements actifs ni leurs propriétés visuelles.
  • La configuration du filtre de paire de fractionnement doit correspondre aux intents utilisés lors du lancement complet des activités. La mise en correspondance intervient au moment où une nouvelle activité est lancée à partir du processus d'application. Il est donc possible qu'elle ne connaisse pas les noms de composants résolus ultérieurement dans le processus système lors de l'utilisation d'intents implicites. Si le nom d'un composant n'est pas connu au moment du lancement, vous pouvez utiliser un caractère générique ("*/*") à la place, et un filtrage basé sur l'action d'intent.
  • Il n'existe actuellement aucun moyen de déplacer des activités entre des conteneurs, ni de les ajouter à un écran fractionné ou de les en sortir après leur création. Les écrans fractionnés ne sont créés par la bibliothèque WindowManager que lorsque de nouvelles activités avec des règles associées sont lancées. Les fractionnements sont entièrement éliminés à l'arrêt de la dernière activité dans un écran fractionné.
  • Les activités peuvent être redémarrées lorsque la configuration change. Dès lors, lorsqu'un fractionnement est créé ou supprimé et que les limites de l'activité changent, celle-ci peut subir une destruction complète, puis être créée à nouveau. Par conséquent, les développeurs d'applications doivent prêter attention à des comportements spécifiques tels que le lancement de nouvelles activités à partir de rappels de cycle de vie.

Ressources supplémentaires