Licence CC BY-SA

Fragment

Tout comme les activités, il existe un fragment « générique ». Il peut inclure des listes, des écrans de préférences et toutes les vues du framework Android pour constituer des portions d’interfaces. Par la suite, elles pourront être réutilisées plusieurs fois dans les écrans de l’application finale. Pour expliquer en profondeur tous ces concepts, une explication détaillée des fragments est donnée dans la suite de ce chapitre.

Introduction aux fragments

Qu’est ce qu’un fragment ?

Les fragments ne sont pas simples à comprendre. Cette notion est souvent confuse pour les débutants et pas toujours bien comprise par les développeurs expérimentés. En effet, les possibilités offertes sont nombreuses et intéressantes. Les fragments sont à mi-chemin entre les activités et les vues. Il ne s’agit ni de l’un, ni de l’autre mais ils sont étroitement liés avec ces concepts. Les fragments permettent de définir des morceaux d’interfaces, un ensemble de vues, qu’il est possible de contrôler et de réutiliser sur plusieurs écrans.

En temps normal, une application est destinée à être exécutée aussi bien sur les smartphones que sur les tablettes, et peu à peu sur les télévisions connectées. La taille des écrans devient de plus en plus grande. Il faut pouvoir exploiter l’espace efficacement sur chacune de ces plates-formes et, si possible, à partir d’un seul projet. Ce dernier point sera expliqué bien plus tard dans ce cours au vue de sa complexité.

Par exemple, le propriétaire d'un blog pourrait légitimement vouloir développer sa propre application pour offrir une alternative mobile à ses lecteurs. Dans un blog simpliste, il voudrait permettre une consultation de ses articles et des commentaires associés. Une version smartphone consisterait dans l’affichage de trois écrans : une liste des articles du blog, l’article courant que le lecteur consulte et les commentaires associés. Sur une tablette en mode paysage, il est possible de restreindre les écrans à un seul en affichant la liste des articles à gauche et l’article et ses commentaire à droite.

Ce genre de chose est possible grâce aux fragments !

Le cycle de vie des fragments

Les activités sont régulées par un cycle de vie. Les fragments possèdent des similitudes sur ce point avec les activités. Ils définissent une interface qu’ils contrôlent mais ils ne sont pas associés à un écran. Ils ne font que s’y attacher. C’est la raison pour laquelle leurs cycles de vie sont semblables mais pas identiques. Ils possèdent les méthodes callback d’une activité, à savoir onCreate, onStart, onResume, onPause, onStop et onDestroy. Ces méthodes ont le même objectif que dans une activité. Elles ne seront pas (ou peu) expliquées. La documentation donne des informations à ce sujet en cas d’oubli.

Plusieurs nouvelles méthodes ont été rajoutées à travers ce cycle de vie. Elles sont liées à l’activité hôte en cours d’exécution. Il ne faut pas perdre à l’esprit qu’un fragment n’est qu'attaché à une activité. Les méthodes supplémentaires sont liées à cette activité. La documentation met à disposition un schéma pour donner le cycle de vie.

Cycle de vie des fragments disponible à partir du site des développeurs Android

Les méthodes rajoutées sont onAttach, onCreateView, onActivityCreated, onDestroyView et onDetach. Les noms de ces méthodes sont assez explicites. Deux sont destinées à la liaison avec l’activité hôte, deux autres à la création de la vue qui compose le fragment et la dernière après la création de l’activité hôte. Elles seront expliquées plus en détail dans la suite de ce chapitre ainsi que dans les suivants de cette partie.

La bibliothèque de compatibilité

Le fragment est une nouveauté depuis Android 3.x. A partir de cette version, il est possible de les placer librement aux endroits voulus pour rendre les applications plus souples et les architecturer convenablement. Cependant, la version 2.3 d’Android est encore largement utilisée, surtout dans les smartphones d’entrée de gamme mais ils ne peuvent pas utiliser les fragments.

Pourquoi ne pas avoir intégré les fragments dès le début ? Google n’a pas pu voir assez loin sur le long terme. Au début, Android était dédié uniquement aux smartphones. Les écrans avaient des tailles différentes en fonction du constructeur, voire du modèle, mais le marché des tablettes était presque inexistant. Les tailles ne dépassaient pas le 4 pouces.

Une fois que les tablettes ont commencées à être commercialisées en grande quantité, Google a été contraint d’offrir une alternative pour ce type d’appareil. La version 3.x d’Android était destinée à résoudre le problème mais ce n’est qu’à partir de la version 4 qu’un tournant a pu être noté. Le plus grand défaut de la troisième version du système était sa philosophie. Même s’il était meilleur que les versions précédentes, il n’était pas prévu pour les smartphones.

Aujourd'hui, de plus en plus de télévisions connectées sur Android sont commercialisées. Il est tout à fait possible de développer pour ce genre d'appareil mais les bonnes pratiques d'ergonomie sont encore un peu vagues. C'est pourquoi, aucun exemple concret ne sera montré mais les techniques apprises dans ce tutoriel le permettront.

Dans le but de ne pas devoir créer un projet pour chaque version d’Android, Google a développé une bibliothèque de compatibilité qu’il est possible d’utiliser dans n’importe quel projet. Cette bibliothèque donne accès à presque toutes les nouvelles notions qu’apporte la version 3.x mais aussi la 4.x qui apporte son lot de nouveautés (elles seront expliquées dans la seconde partie).

Grâce à cette bibliothèque, les applications développées toucheront plus de 90% du marché des appareils. Raison pour laquelle toutes les notions apprises seront basées sur son utilisation dès que possible. Il est également conseillé de développer avec ce projet même si l’application finale n’est pas destinée à être compatible avec les anciennes versons. Personne ne sait de quoi est fait demain.

Utiliser des fragments fixes

La théorie maintenant terminée, la pratique permet d’en comprendre réellement le fonctionnement. Il existe deux façons d’intégrer des fragments à une activité : de manière fixe en spécifiant les fragments dans le fichier XML d’affichage de l’écran voulu et dynamiquement avec l’aide des outils mis à la disposition des développeurs dans le framework Android.

Création d’un fragment

La création d’un fragment est similaire à la création d’une activité. La portion d’interface se déclare dans un fichier XML d’affichage. Il est désérialisé dans une classe qui étend la classe Fragment et non plus Activity. Cependant, même si les fragments peuvent redéfinir la méthode public void onCreate (Bundle savedInstanceState), y appeler la méthode setContentView(int resource) ne fonctionnera pas pour la désérialisation.

Il est possible de redéfinir la méthode suivante dans son cycle de vie, public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState). Elle donne accès en premier paramètre à un « inflater » qui permet la désérialisation du fichier XML d’affichage.

La bibliothèque de compatibilité a été présentée. Son utilisation sera constante dans les exemples illustrant le tutoriel. Il existe une chose importante à savoir sur son utilisation : l’environnement de travail, peu importe lequel, proposera d’importer deux paquetages pour avoir accès à Fragment et aux autres classes présentées dans ce tutoriel. Pour les fragments, il proposera android.app.Fragment et android.support.v4.app.Fragment.

Toutes les classes figurant dans les paquetages android.support.v4 possèdent un équivalent limité à une certaine API (à partir de la version 3.x d’Android jusqu’aux versions récentes). Quant à la bibliothèque de compatibilité, elle apporte une compatibilité à partir de la version 2.x. L’utilisation des classes de cette bibliothèque diffère peu de l’originale mais il y a certaines subtilités à connaître. Le tutoriel enseignera son utilisation plutôt que les originaux pour deux raisons :

  • Il est plus simple de passer de l’utilisation de la librairie de compatibilité vers les originaux que l’inverse ;
  • Les originaux restreignent la portée de l’application finale au minimum à la version 3.x d’Android, voire plus comme les notifications avancées qui ne sont compatibles qu’à partir de la version 4.1.

Les raisons pour utiliser la bibliothèque de compatibilité sont intéressantes mais il y a une chose essentielle à savoir : il n’est pas possible de mélanger les originaux avec les classes du support. C’est une erreur commune chez les développeurs. Google a tenté de rendre l’utilisation de la bibliothèque la plus proche de son utilisation normale. Mise à part quelques méthodes et des noms de classes, l’utilisation sera identique. Cela peut paraître pratique mais une erreur est vite arrivée.

Un fragment simple serait d’afficher simplement du texte. Le but de cet exemple n’est pas de confectionner un fragment complexe (ce loisir sera donné plus tard). L’idée est de placer un TextView au centre de l’écran via un fichier XML d’affichage. Il sera désérialisé dans un fragment qui sera lui même contenu dans une activité. Voici le fichier XML d’affichage fragment_fixe :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/title_fragment_fixe" />

</RelativeLayout>

Pour ce premier exemple, le fragment associé est extrêmement simple. En temps normal, un fragment joue le contrôleur complet de la portion d’interface qu’il contient afin d’alléger l’activité hôte et d’architecturer convenablement le projet. Ainsi, le fragment FixeFragment ressemble à ceci :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package com.siteduzero.android.fragments.fixe;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.siteduzero.android.R;

public class FixeFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_fixe, container, false);
    }
}

Remarquez que les importations sont délibérément affichées afin de montrer que la bibliothèque de compatibilité est bien utilisée à la place des originaux. Cela sera une habitude prise dans ce tutoriel pour que vous ne soyez jamais perdus.

La création et l’utilisation d’un fragment est aussi simple qu’une activité. Il faut maintenant attacher ce fragment à une activité. Il n’y a aucun changement de ce côté là puisqu’un fragment peut être déclaré dans un fichier XML d’affichage comme n’importe quelle vue. Il sera chargé dans une activité à l’exécution de l’application et ne changera plus. Dans ce cas, il sera fixé à l’activité hôte. Ses attributs sont les mêmes qu’une vue normale mais, en plus, il faut rajouter le chemin d'accès vers le fragment. Pour attacher notre fragment FixeFragment, il faut le déclarer ainsi :

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_fixe"
    android:name="com.siteduzero.android.fragments.fixe.FixeFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Du côté de l’activité, il y a une petite chose à savoir. Il n’est pas possible d’étendre la classe Activity si la bibliothèque de compatibilité est utilisée. Une autre classe est présente dans le support, FragmentActivity. Cette classe est l’équivalente à la classe originale, Activity. Mais elle ne doit pas être utilisée si les originaux sont utilisés.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package com.siteduzero.android.fragments.fixe;

import com.siteduzero.android.R;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

public class FixeActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        setContentView(R.layout.activity_fragment_fixe);
    }
}

Tout comme le fragment, l’activité est vide puisque le fragment est fixe et que toute l’interface y a été déportée. C’est l’une des forces de l’utilisation des fragments. Habituellement, les activités jouent le rôle des contrôleurs dans une architecture MVC (patron architectural sur lequel Android se base dans le développement d’applications) mais cette partie contrôleur a été allégée pour ne plus avoir des activités énormes et pour devenir les contrôleurs des fragments plutôt que directement des interfaces. Cela permet de maintenir plus aisément le code et de séparer les responsabilités des différentes classes.

Résultat de l'exécution de l'activité FixeActivity

Réarranger les fragments en paysage

Attacher un fragment de manière fixe à une activité n’empêche pas d’en attacher plusieurs, qu’ils soient identiques ou non. Il suffit de spécifier plusieurs fragments dans le fichier XML d’affichage de l’activité pour voir apparaître les fragments. Une possibilité pour l’illustrer est le mode paysage.

Une application n’est pas toujours destinée à s’afficher en portrait (sauf en cas de contre indication dans le fichier Manifest) ni même toujours sur un smartphone. C’est pourquoi, en mode paysage, il faut repenser les interfaces pour garder une expérience utilisateur optimale.

Dans un dossier res/layout-land, il faut créer un nouveau fichier XML d’affichage du même nom que celui dans le dossier res/layout de l’activité cible, FixeActivity dans l’exemple ci-présent. Tout comme n’importe quelle vue, les fragments peuvent être placés dans un conteneur comme le LinearLayout afin de donner un poids équitable entre les fragments.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false"
    android:orientation="horizontal" >

    <fragment
        android:id="@+id/fragment1"
        android:name="com.siteduzero.android.fragments.fixe.FixeFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <fragment
        android:id="@+id/fragment2"
        android:name="com.siteduzero.android.fragments.fixe.FixeFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>

Résultat de l'exécution de l'activité FixeActivity en paysage

Utiliser des fragments dynamiques

Les fragments fixes sont simples à implémenter. A partir du moment où le fragment est codé, il suffit de l’indiquer dans des fichiers XML d’affichage à désérialiser dans une activité sans rien indiquer en plus. Se limiter à ce type de fragment ne permettrait pas de satisfaire ses promesses de flexibilité et de maintenance.

Dans cet ordre idée, le framework Android fournit une API pour gérer les fragments pendant l’exécution d’une application. Ainsi, il est possible de remplacer un fragment par un autre aisément et, par la même occasion, afficher une nouvelle portion d’interface.

Gérer ses fragments

Le framework Android met à disposition des développeurs une API indispensable pour gérer les fragments, FragmentManager. Cette API offre plusieurs services. La documentation donne toutes les informations à ce sujet. Dans l’immédiat, le plus intéressant est le service qui permet de gérer des transactions via une autre API, FragmentTransaction. Les transactions permettent d’opérer sur les fragments de manière groupée. Les opérations sont classiques. Il est possible d’ajouter, remplacer, supprimer, etc. des fragments. Elles ne seront pas toutes expliquées dans ce tutoriel.

L’utilisation de ces APIs est assez simple mais il faut garder à l’esprit que la bibliothèque de compatibilité est utilisée dans les exemples. La documentation donnée renseigne les méthodes des classes originales du framework. Même si les signatures des méthodes sont globalement les mêmes pour chacune d’elles, il arrive que quelques unes changent. Notamment avec l’ajout du mot clé « Support ». Par exemple, pour récupérer un FragmentManager, la méthode utilisée sera public FragmentManager getSupportFragmentManager() plutôt que public FragmentManager getFragmentManager().

Il faut rappeler que les fragments qui viennent du paquetage android.app.Fragment ne peuvent pas être utilisés avec les classes de la bibliothèque de compatibilité (et inversement). Dans les exemples de ce tutoriel, Fragment et FragmentManager viennent tous les deux du projet de compatibilité. Dans le cas contraire, l’application provoquera instantanément une erreur forcée.

Le contrôleur des fragments

Jusqu’à présent, le contrôleur des interfaces était les activités. Elles se chargeaient de désérialiser les fichiers XML et de récupérer les composants graphiques pour y ajouter un comportement et des évènements. Dorénavant, les fragments jouent ce rôle et les activités deviennent les contrôleurs des fragments. A savoir, les contrôleurs des contrôleurs.

Il est essentiel de comprendre que les fragments ne sont pas vraiment des nouveautés dans leur rôle. Il y a qu’une déportation du code d’un concept à un autre. Le réel changement se situe dans les activités puisqu’ils doivent gérer les fragments. Son changement de rôle est la réelle nouveauté.

Les fragments fixes n’illustrent pas clairement ce principe. Même si le framework se charge d’utiliser l’API de gestion des fragments, il n’est pas visuel pour le développeur. Pour l’illustrer, deux fragments simples ont été confectionnés. Ils contiennent un TextView pour afficher le nom du fragment courant et un Button pour remplacer le fragment courant par le suivant. Ils ne sont pas compliqués à développer. Leurs réalisations sont disponibles sur le projet GitHub de ce tutoriel. Ils sont nommés Dynamic1Fragment et Dynamic2Fragment. Quant à l’activité, elle a été nommée DynamicActivity. Plusieurs choses sont à savoir sur sa réalisation.

Première chose, son fichier XML d'affichage ne comportera aucun fragment mais un FrameLayout avec un identifiant pour pouvoir le récupérer dans l’activité et remplacer son contenu par celui d'un fragment. Pour rappel, ce conteneur permet de superposer des vues à un même endroit sur l’écran. Son utilisation sera plus claire par la suite.

Seconde chose, pour des soucis de structuration et d’apprentissage, une certaine architecture simpliste sera mise en place. Dans la méthode public void onCreate(Bundle savedInstanceState), une méthode sera appelée : private void showFragment(final Fragment fragment). Elle affiche le fragment donné en paramètre. Elle sera appelée dans la méthode onCreate(...) et lorsque l’utilisateur cliquera sur le bouton du fragment.

Initialisation des fragments

L’initialisation des fragments se fait par simple instanciation d’un objet d’un fragment confectionné précédemment. Par exemple, pour le premier fragment dynamique, il faudra procéder de la manière suivante : Dynamic1Fragment dynamic1Fragment = new Dynamic1Fragment();. Cependant, comme il n’existe pas de petites économies, une optimisation possible serait d’instancier les deux fragments comme attribut de l’activité.

1
2
3
// We instantiate just one time fragments during the life of the activity.
private final Dynamic1Fragment mDynamic1Fragment = new Dynamic1Fragment();
private final Dynamic2Fragment mDynamic2Fragment = new Dynamic2Fragment();

Cette économie convient pour notre exemple mais nous verrons que cela changera bien vite lorsque l'application deviendra plus complexe.

Remplacer les fragments

Afficher le fragment à l’écran est la réelle nouveauté dans le développement de fragments dynamiques. L’idée est de remplacer le contenu du conteneur, FrameLayout, par un fragment donné. Pour ce faire, il est nécessaire d’utiliser l’API des transactions des fragments, FragmentTransaction. Sa documentation indique toutes méthodes utiles.

Plusieurs sont utilisées dans showFragment(final Fragment fragment) :

  • public abstract FragmentTransaction setCustomAnimations (int enter, int exit) : Anime la transition d’un fragment à un autre en donnant l’animation d’entrée pour le nouveau fragment et l’animation de sortie pour l’ancien ;
  • public abstract FragmentTransaction replace (int containerViewId, Fragment fragment) : Remplace le contenu d’un conteneur, donné en premier paramètre, par un nouveau fragment ;
  • public abstract FragmentTransaction addToBackStack (String name) : Indique une valeur null pour retourner au précédent fragment lorsque l’utilisateur cliquera sur le bouton « Back ».

Au final, la méthode s’implémentera de la façon suivante :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
private void showFragment(final Fragment fragment) {
    if (fragment == null) {
        return;
    }

    // Begin a fragment transaction.
    final FragmentManager fm = getSupportFragmentManager();
    final FragmentTransaction ft = fm.beginTransaction();
    // We can also animate the changing of fragment.
    ft.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
    // Replace current fragment by the new one.
    ft.replace(R.id.frameLayoutListView, fragment);
    // Null on the back stack to return on the previous fragment when user
    // press on back button.
    ft.addToBackStack(null);

    // Commit changes.
    ft.commit();
}

Chaque transaction doit appeler la méthode commit() pour voir ses opérations s'effectuer. En cas contraire, aucune erreur ne sera lancée mais rien ne se passera.

Retenir sa position dans les fragments

Une astuce intéressante est de garder en mémoire le fragment affiché à l’écran après une reconstruction de l’activité. Il faut toujours privilégier l’expérience utilisateur. Se souvenir de lui et de ses manipulations est un bon début dans cette idée. C’est pourquoi, un nouvel attribut va figurer dans la classe pour retenir le fragment courant. Il suffira alors de le sauvegarder via la méthode public void onSaveInstanceState(Bundle outState).

Le changement se fera dans la méthode onCreate(...) de l’activité puisqu’il faut afficher le fragment courant s’il existe en mémoire. La méthode sera complétée de la façon suivante :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
if (savedInstanceState != null) {
    mFragment = savedInstanceState.getString(KEY_FRAGMENT);
} else {
    mFragment = getIntent().getStringExtra(KEY_FRAGMENT);
}

if (mFragment != null) {
    if (mFragment.equals(mDynamic1Fragment.getClass().getSimpleName())) {
        showFragment(this.mDynamic1Fragment);
    } else if (mFragment.equals(mDynamic2Fragment.getClass().getSimpleName())) {
        showFragment(this.mDynamic2Fragment);
    }
} else {
    showFragment(this.mDynamic1Fragment);
}

Il faut remarquer qu’une touche de réfléxivité est utilisée dans l’exemple ci-dessus. mDynamic1Fragment.getClass().getSimpleName() renvoie le nom de la classe, à savoir Dynamic1Fragment. Il faut donc sauvegarder dans mFragment une valeur similaire qui se fera dans la méthode private void showFragment(final Fragment fragment) de la même manière avec la variable fragment. Ainsi, le fragment courant est sauvegardé.

Résultat final

Avant de montrer le résultat final, il reste une problématique a résoudre : comment capturer l’évènement des boutons des fragments dans l’activité hôte ? En effet, les fragments n’ont pas accès à FragmentManager, ou plutôt, ce n’est pas leur rôle de contrôler les autres fragments. En tant normal, il faut utiliser les listeners mais cette pratique sera expliquée plus tard. La technique utilisée est plus simple pour un premier aperçu des fragments dynamiques. Il faut utiliser un nouveau attribut dans les fichiers XML d’affichage des fragments sur les éléments Button : android:onClick. Cet attribut permet de définir une méthode Java qui sera appelée automatiquement lorsque l’utilisateur cliquera dessus.

Il n'y a que deux restrictions :

  • La signature de la méthode doit être public, renvoyer void et avoir un seul paramètre du type View ;
  • Elle doit être déclarée dans une activité.

Les méthodes ressembleront à ceci pour des attributs avec les valeurs goToFragment2 et goToFragment1 :

1
2
3
4
5
6
7
public void goToFragment1(View v) {
    showFragment(this.mDynamic1Fragment);
}

public void goToFragment2(View v) {
    showFragment(this.mDynamic2Fragment);
}

L’exécution de l’application permet d’afficher un premier fragment avec un TextView qui ne change pas et un bouton qui propose à l’utilisateur d’afficher le second écran. Lorsqu’il cliquera dessus, une animation sera exécutée vers le nouveau fragment. Lorsqu’il cliquera sur le bouton « Back », il reviendra au précédent fragment. Le résultat est le suivant :

Résultat de l'exécution de l'activité DynamicActivity

Attacher un bundle

Les fragments deviennent les contrôleurs des interfaces qu’ils désérialisent et ils sont indépendants les uns des autres. C’est la force de ce nouveau concept mais il peut arriver, suivant les situations, qu’à l’initialisation d’un fragment, des données soient nécessaires. Un exemple simple serait de donner l’identifiant d’un article. Sur base de cette donnée, le fragment peut récupérer toutes les informations de l’article en question soit par un service web ou dans la base de données interne de l’application.

Les bundles ne sont pas utilisés qu’avec les activités. Les fragments aussi peuvent les utiliser. Seulement, il n’est pas question d’Intent avec les fragments puisqu’ils sont gérés par une autre API. La méthode avec les fragments est légèrement moins bien pensée que celle avec les activités. Il faut instancier un fragment, un bundle en plaçant les informations dedans et l’attacher au fragment avec la méthode public void setArguments (Bundle args).

1
2
3
4
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
args.putInt(KEY_ID, id);
fragment.setArguments(args);

Cette simple solution suffirait mais elle rencontre un problème : si l’instanciation d’un même fragment avec un bundle se fait plusieurs fois dans l’application, il faut faire une répétition du code assez conséquente et la maintenir en cas de modification. Pour palier à cette répétition qui alourdie considérablement le code, une bonne pratique est de créer une méthode statique dans le fragment en question. Cela permet d’encapsuler toutes les informations dans le fragment et de ne pas tout éparpiller dans le code. Cette méthode ressemblera à :

1
2
3
4
public static MyFragment newInstance(
/* informations que je veux donner à mon fragment */) {
    // renvoie une instance de mon fragment
}

Pour rappel, static signifie que la méthode n’est pas directement attachée aux instances créé de la classe hôte. Par exemple, il est possible de créer des instances de la classe hôte dans cette méthode.

En reprenant l’exemple de l’identifiant à passer au fragment pour afficher le contenu de l’article sélectionné, il suffit de passer cet entier en paramètre, de reprendre le code précédemment donné et de renvoyer le fragment. Ainsi, dans le code de l’application, il suffira d’appeler la méthode MyFragment.newInstance(idArticle); pour automatiquement créer un fragment avec le bundle attaché et de modifier le code à un seul endroit en cas de changements.

Pour récupérer les informations contenues dans le bundle du fragment, rien de plus simple. Les arguments sont accessibles par sa méthode d’accès public final Bundle getArguments () qui renvoie le bundle précédemment attaché au fragment et d’en récupérer les données grâce aux identifiants donnés à chacune.


En résumé

  • Un fragment est une portion d'interface qui peut être attaché à plusieurs activités différentes.
  • Il possède son propre cycle de vie mais il est étroitement lié à son activité hôte.
  • La bibliothèque de compatibilité Google permet de rendre les applications compatibles à partir des terminaux sur Android 2.1 et supérieur.
  • Les fragments fixes sont attachés directement dans le fichier XML d'affichage de l'activité.
  • Les fragments dynamiques sont attachés pendant l'exécution de l'application via une API, FragmentManager.