1. Les bases d'Android▲
La suite de cet article suppose que vous avez déjà une connaissance basique du développement sous Android.
2. Les fragments▲
2-1. Qu'est-ce qu'un fragment ?▲
Un fragment est un composant indépendant qui peut être utilisé dans une activité. Un fragment encapsule des fonctionnalités qui le rendent facile à réutiliser dans une activité ou dans une mise en page.
Un fragment s'exécute dans le contexte d'une activité, mais possède son propre cycle de vie et typiquement, il possède une interface utilisateur. Il est aussi possible de définir des fragments sans interface utilisateur, par exemple des fragments sans entête.
Les fragments peuvent être ajoutés à une activité de manière statique ou dynamique.
2-2. Avantages de l'utilisation des fragments▲
Les fragments permettent une réutilisation plus facile dans différentes mises en page. Par exemple, vous pouvez construire des mises en page avec un seul panneau pour des téléphones et plusieurs panneaux pour des tablettes. Ce n'est pas limité aux tablettes, vous pouvez aussi supporter les différentes mises en page suivant l'orientation (portrait ou paysage) du téléphone.
L'exemple typique est une liste dans une activité. Sur une tablette vous pouvez voir les détails immédiatement sur la partie droite si vous cliquez sur un élément. Sur un téléphone, vous affichez une nouvelle fenêtre avec les détails. Ceci est représenté par le schéma suivant :
La discussion suivante suppose que vous avez deux fragments (principal et détail), mais vous pouvez aussi en avoir plus. Nous aurons aussi une activité principale et une activité détaillée. Sur une tablette, l'activité principale contient les deux fragments dans sa mise en page, sur un téléphone, elle ne contient que l'activité principale.
Le schéma suivant montre cette utilisation :
2-3. Comment utiliser les fragments ?▲
Pour créer différentes mises en page avec des fragments, vous pouvez :
- utiliser une activité qui affiche deux fragments sur les tablettes et un seul sur les téléphones. Dans ce cas, vous basculerez les fragments dans l'activité en cas de besoin. Cela requiert que le fragment ne soit pas déclaré dans le fichier de mise en page de manière à ce qu'il puisse être supprimé de façon dynamique. Cela requiert aussi des modifications dans la barre d'actions si le statut de la barre d'actions dépend du fragment affiché ;
- utiliser des activités séparées pour héberger chacun des fragments sur un téléphone. Par exemple quand l'interface utilisateur d'une tablette utilise deux fragments dans une activité, utilisez la même activité pour un téléphone, mais en fournissant une mise en page alternative qui ne comprend qu'un seul fragment. Quand vous devez changer de fragment, vous démarrez une autre activité qui héberge l'autre fragment.
La deuxième approche est la plus flexible et en général la méthode privilégiée pour utiliser des fragments. Dans ce cas, l'activité principale vérifie que le fragment détaillé est disponible dans la mise en page. S'il est présent, l'activité principale l'informe de se mettre à jour. Si le fragment détaillé n'est pas présent, l'activité principale démarre l'activité détaillée.
3. Définir et utiliser des fragments▲
3-1. Définir des fragments▲
Pour définir un nouveau fragment, vous surchargez soit la classe android.app.Fragment soit une de ses sous-classes, par exemple ListFragment, DialogFragment, PreferenceFragment or WebViewFragment. Le code suivant vous montre un exemple d'implémentation :
package
com.example.android.rssfeed;
import
android.app.Fragment;
import
android.os.Bundle;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.TextView;
public
class
DetailFragment extends
Fragment {
@Override
public
View onCreateView
(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view =
inflater.inflate
(
R.layout.fragment_rssitem_detail,
container, false
);
return
view;
}
public
void
setText
(
String item) {
TextView view =
(
TextView) getView
(
).findViewById
(
R.id.detailsText);
view.setText
(
item);
}
}
3-2. Ajouter un fragment de manière statique▲
Pour utiliser votre nouveau fragment, vous pouvez l'ajouter de manière statique au fichier de mise en page XML.
Pour vérifier si le fragment est présent dans votre mise en page, vous pouvez utiliser la classe FragmentManager.
DetailFragment fragment =
(
DetailFragment) getFragmentManager
(
).
findFragmentById
(
R.id.detail_frag);
if
(
fragment==
null
||
!
fragment.isInLayout
(
)) {
// start new Activity
}
else
{
fragment.update
(
...);
}
Si un fragment est défini dans le fichier XML, l'attribut android:name indique le nom de la classe correspondante.
3-3. Cycle de vie d'un fragment▲
Un fragment possède son propre cycle de vie, mais il est toujours connecté au cycle de vie de l'activité qui l'utilise.
La méthode onCreate() est appelée après l'appel à la méthode onCreate() de l'activité, mais avant la méthode onCreateView() du fragment.
La méthode onCreateView() est appelée par Android dès que le fragment doit créer son interface utilisateur. Ici, vous pouvez afficher la mise en page avec la méthode inflate() ou l'objet Inflator passé en paramètre à cette méthode. Il n'y a aucun besoin d'implémenter cette méthode pour les fragments sans en-tête.
La méthode onActivityCreated() est appelée après la méthode onCreateView() quand l'activité est créée. Ici vous pouvez instancier les objets qui nécessitent un objet Context.
Les fragments ne sous classent pas le Context. Vous devez utiliser la méthode getActivity() pour obtenir l'activité parente.
La méthode onStart() est appelée une fois que le fragment devient visible.
Si une activité s'arrête, ses fragments sont aussi arrêtés. Si une activité est détruite, ses fragments sont aussi détruits.
3-4. Communication entre l'application et les fragments▲
Pour améliorer la réutilisabilité, les fragments ne devraient pas communiquer directement entre eux. Toutes les communications avec les fragments devraient se faire via l'activité qui les héberge.
Pour cela, un fragment devrait définir une interface comme un type interne pour imposer à l'activité qui veut l'utiliser d'implémenter cette interface. Ceci permet d'éviter que le fragment connaisse l'activité qui l'utilise. Dans la méthode onAttach(), le fragment peut vérifier que l'activité implémente cette interface.
Par exemple, si un fragment doit communiquer une valeur à son activité, cela peut être fait de cette façon :
package
com.example.android.rssfeed;
import
android.app.Activity;
import
android.app.Fragment;
import
android.os.Bundle;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.Button;
public
class
MyListFragment extends
Fragment {
private
OnItemSelectedListener listener;
@Override
public
View onCreateView
(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view =
inflater.inflate
(
R.layout.fragment_rsslist_overview,
container, false
);
Button button =
(
Button) view.findViewById
(
R.id.button1);
button.setOnClickListener
(
new
View.OnClickListener
(
) {
@Override
public
void
onClick
(
View v) {
updateDetail
(
);
}
}
);
return
view;
}
public
interface
OnItemSelectedListener {
public
void
onRssItemSelected
(
String link);
}
@Override
public
void
onAttach
(
Activity activity) {
super
.onAttach
(
activity);
if
(
activity instanceof
OnItemSelectedListener) {
listener =
(
OnItemSelectedListener) activity;
}
else
{
throw
new
ClassCastException
(
activity.toString
(
)
+
" must implemenet MyListFragment.OnItemSelectedListener"
);
}
}
@Override
public
void
onDetach
(
) {
super
.onDetach
(
);
listener =
null
;
}
// May also be triggered from the Activity
public
void
updateDetail
(
) {
// create a string, just for testing
String newTime =
String.valueOf
(
System.currentTimeMillis
(
));
// Inform the Activity about the change based
// interface defintion
listener.onRssItemSelected
(
newTime);
}
}
4. Données persistantes dans les fragments▲
4-1. Données persistantes entre deux redémarrages de l'application▲
Avec les fragments, vous pouvez aussi avoir besoin de stocker des données applicatives. Pour cela, vous pouvez stocker ces données de manière centralisée. Par exemple :
- dans une base de données Sqlite ;
- dans un fichier ;
- dans l'objet application. Dans ce cas, l'application doit supporter ce type de stockage.
4-2. Données persistantes entre deux changements de configuration▲
Si vous devez stocker des données de configuration, vous pouvez aussi utiliser l'objet application.
En plus, vous pouvez utiliser la méthode setRetainState(true) sur le fragment. Cela sauvegarde l'instance du fragment entre deux changements de configuration, mais cela marche uniquement si le fragment n'est pas ajouté à la pile des tâches de fond (backstack). Cette méthode n'est pas recommandée par Google pour les fragments qui possèdent une interface utilisateur. Dans ce cas, les données doivent être stockées comme des membres (champs).
Si les données qui doivent être sauvegardées sont supportées par la classe Bundle, vous pouvez utiliser la méthode onSaveInstanceState() pour mettre ces données dans le Bundle et les retrouver dans la méthode onActivityCreated().
5. Modifier les fragments dynamiquement▲
Les classes FragmentManager et FragmentTransaction vous permettent d'ajouter, de supprimer et de remplacer des fragments dans la mise en page de votre activité.
Les fragments peuvent être modifiés dynamiquement avec des transactions. Pour ajouter dynamiquement des transactions à une mise en page déjà existante, vous définissez un container dans le fichier XML dans lequel vous pouvez ajouter le fragment. Pour cela, vous pouvez utiliser l'élément FrameLayout.
FragmentTransaction ft =
getFragmentManager
(
).beginTransaction
(
);
ft.replace
(
R.id.your_placehodler, new
YourFragment
(
));
ft.commit
(
);
Un nouveau fragment va remplacer un fragment existant qui a été préalablement ajouté au container.
Si vous voulez ajouter une transition sur la pile des tâches de fond Android (backstack) vous devez utiliser la méthode addToBackStack(). Ceci rajoute l'action dans l'historique de la pile de l'activité et vous pourrez annuler les changements effectués sur le fragment avec le bouton « Back ».
6. Animation des transitions de fragments▲
Durant une transition de fragment, vous pouvez définir des animations basées sur l'API « Property Animation » avec la méthode setCustomAnimations().
Vous pouvez aussi utiliser les animations standard fournies par Android avec la méthode setTransition(). Elles sont définies avec les constantes commençant par FragmentTransaction.TRANSIT_FRAGMENT_*.
Ces deux méthodes permettent de définir une animation en début et en fin.
7. Ajouter des transitions de fragments sur la pile des tâches de fond (backstack)▲
Vous pouvez ajouter une FragmentTransition à la pile des tâches de fond (backstack) pour permettre à l'utilisateur d'utiliser le bouton « back » pour annuler la transition.
Pour cela, il faut utiliser la méthode addToBackStack() sur l'objet FragmentTransition.
8. Fragments pour les traitements en tâche de fond▲
8-1. Fragments sans en-tête▲
Les fragments peuvent être utilisés sans définir d'interface utilisateur.
Pour créer un fragment sans entête, il faut tout simplement retourner NULL dans la méthode onCreateView() de votre fragment.
Il est recommandé d'utiliser des fragments sans entête pour le traitement en tâche de fond en combinaison avec la méthode setRetainInstance(). De cette manière, vous n'avez pas à gérer vous-même les changements durant le traitement asynchrone.
8-2. Mémoriser les fragments sans en-tête pour gérer les changements de configuration▲
Les fragments sans en-tête sont typiquement utilisés pour mémoriser un état avant des changements de configuration ou alors pour des traitements en tâche de fond. Pour cela, vous devez mémoriser votre fragment sans en-tête. Un fragment mémorisé n'est pas détruit lors des changements de configuration.
Pour mémoriser votre fragment, il faut appeler sa méthode setRetainInstance().
Pour ajouter un tel fragment à votre activité, il faut utiliser la méthode add de la classe FragmentManager. Si vous devez vous référer à ce segment plus tard, vous devez l'ajouter avec un tag de façon à pouvoir le retrouver ultérieurement avec la méthode findFragmentByTag() de la classe FragmentManager.
L'usage de onRetainNonConfigurationInstance() est obsolète et devrait être remplacé par un fragment sans entête.
9. Contribuer à la barre d'actions▲
Les fragments peuvent aussi influer sur la barre d'actions. Pour cela, appelez setHasOptionsMenu() dans la méthode onCreate() du fragment. Dans ce cas, le système Android appelle la méthode onCreateOptionsMenu() du fragment et ajoute les options du menu à celles déjà ajoutées par l'activité.
10. Exercice avec les fragments▲
10-1. Présentation▲
Le tutoriel suivant montre comment utiliser les fragments. L'application utilise une mise en page différente avec des fragments dépendant du mode portrait ou paysage.
Dans le mode portrait, l'activité RssfeedActivity montre un seul fragment. Depuis ce fragment, l'utilisateur peut naviguer vers une autre activité qui contient un autre fragment.
Dans le mode paysage, l'activité RssfeedActivity montre les deux fragments côte à côte.
10-2. Création du projet▲
Créez un nouveau projet Android avec les données suivantes :
Propriété |
Valeur |
Nom de l'application |
RSS Reader |
Nom du projet |
com.example.android.rssfeed |
Nom du paquetage |
com.example.android.rssfeed |
Modèle |
BlankActivity |
Activité |
RssfeedActivity |
Mise en page |
activity_rssfeed |
Table 1. Android project
10-3. Création des mises en page▲
Créez ou modifiez le fichier de mise en page dans le répertoire res/layout/.
Créez un nouveau fichier de mise en page nommé fragment_rssitem_detail.xml. Ce fichier de mise en page sera utilisé par le fragment DetailFragment.
<?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
:
orientation
=
"vertical"
>
<TextView
android
:
id
=
"@+id/detailsText"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"match_parent"
android
:
layout_gravity
=
"center_horizontal|center_vertical"
android
:
layout_marginTop
=
"20dip"
android
:
text
=
"Default Text"
android
:
textAppearance
=
"?android:attr/textAppearanceLarge"
android
:
textSize
=
"30dip"
/>
</LinearLayout>
Créez un nouveau fichier de mise en page nommé fragment_rsslist_overview.xml. Ce fichier de mise en page sera utilisé par le fragment MyListFragment.
<?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
:
orientation
=
"vertical"
>
<Button
android
:
id
=
"@+id/button1"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"Press to update"
/>
</LinearLayout>
Modifiez le fichier activity_rssfeed.xml existant. Ce fichier est la mise en page par défaut pour l'activité RssfeedActivity et elle affiche les deux fragments.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"fill_parent"
android
:
orientation
=
"horizontal"
>
<fragment
android
:
id
=
"@+id/listFragment"
android
:
layout_width
=
"0dp"
android
:
layout_weight
=
"1"
android
:
layout_height
=
"match_parent"
android
:
layout_marginTop
=
"?android:attr/actionBarSize"
class
=
"com.example.android.rssfeed.MyListFragment"
></fragment>
<fragment
android
:
id
=
"@+id/detailFragment"
android
:
layout_width
=
"0dp"
android
:
layout_weight
=
"2"
android
:
layout_height
=
"match_parent"
class
=
"com.example.android.rssfeed.DetailFragment"
>
<!-- Preview: layout=@layout/details -->
</fragment>
</LinearLayout>
10-4. Création des classes Fragment▲
Maintenant, il faut créer les classes Fragment. Commençons par la classe DetailFragment.
package
com.example.android.rssfeed;
import
android.app.Fragment;
import
android.os.Bundle;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.TextView;
public
class
DetailFragment extends
Fragment {
@Override
public
View onCreateView
(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view =
inflater.inflate
(
R.layout.fragment_rssitem_detail,
container, false
);
return
view;
}
public
void
setText
(
String item) {
TextView view =
(
TextView) getView
(
).findViewById
(
R.id.detailsText);
view.setText
(
item);
}
}
Créons la classe MyListFragment. Malgré son nom, elle ne va pas afficher une liste, elle aura juste un bouton permettant d'envoyer la date courante au fragment détaillé.
package
com.example.android.rssfeed;
import
android.app.Activity;
import
android.app.Fragment;
import
android.os.Bundle;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.Button;
public
class
MyListFragment extends
Fragment {
private
OnItemSelectedListener listener;
@Override
public
View onCreateView
(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view =
inflater.inflate
(
R.layout.fragment_rsslist_overview,
container, false
);
Button button =
(
Button) view.findViewById
(
R.id.button1);
button.setOnClickListener
(
new
View.OnClickListener
(
) {
@Override
public
void
onClick
(
View v) {
updateDetail
(
);
}
}
);
return
view;
}
public
interface
OnItemSelectedListener {
public
void
onRssItemSelected
(
String link);
}
@Override
public
void
onAttach
(
Activity activity) {
super
.onAttach
(
activity);
if
(
activity instanceof
OnItemSelectedListener) {
listener =
(
OnItemSelectedListener) activity;
}
else
{
throw
new
ClassCastException
(
activity.toString
(
)
+
" must implemenet MyListFragment.OnItemSelectedListener"
);
}
}
// May also be triggered from the Activity
public
void
updateDetail
(
) {
// create fake data
String newTime =
String.valueOf
(
System.currentTimeMillis
(
));
// Send data to Activity
listener.onRssItemSelected
(
newTime);
}
}
10-5. L'activité RssfeedActivity▲
Modifiez la classe RssfeedActivity avec le code suivant :
package
com.example.android.rssfeed;
import
android.os.Bundle;
import
android.app.Activity;
import
android.view.Menu;
public
class
RssfeedActivity extends
Activity implements
MyListFragment.OnItemSelectedListener{
@Override
protected
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
setContentView
(
R.layout.activity_rssfeed);
}
// if the wizard generated an onCreateOptionsMenu you can delete
// it, not needed for this tutorial
@Override
public
void
onRssItemSelected
(
String link) {
DetailFragment fragment =
(
DetailFragment) getFragmentManager
(
)
.findFragmentById
(
R.id.detailFragment);
if
(
fragment !=
null
&&
fragment.isInLayout
(
)) {
fragment.setText
(
link);
}
}
}
10-6. Exécution▲
Exécutez votre exemple. Les deux fragments devraient être affichés en mode portrait et paysage. Si vous appuyez sur le bouton dans le fragment ListFragment, le fragment DetailFragment devrait être mis à jour.
11. Exercice avec les fragments, utilisation du mode portrait▲
11-1. Création des mises en page pour le mode portrait▲
L'activité RssfeedActivity doit utiliser un fichier de mise en page particulier en mode portrait. En mode portrait, Android va vérifier le répertoire layout-port pour les fichiers correspondants. Si Android ne trouve pas de fichier correspondant, il utilise le répertoire layout.
Pour cela, il faut créer un répertoire res/layout-port. Après cela, créez le fichier de mise en page activity_rssfeed.xml dans le répertoire res/layout-port.
<?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
:
orientation
=
"horizontal"
>
<fragment
android
:
id
=
"@+id/listFragment"
android
:
layout_width
=
"match_parent"
android
:
layout_height
=
"match_parent"
android
:
layout_marginTop
=
"?android:attr/actionBarSize"
class
=
"com.example.android.rssfeed.MyListFragment"
/>
</LinearLayout>
Créez aussi le fichier de mise en page activity_detail.xml. Cette mise en page sera utilisée par l'activité DetailActivity. Notez que l'on aurait aussi pu le créer dans le répertoire res/layout mais il n'est utilisé qu'en mode portrait c'est pourquoi nous le plaçons dans ce répertoire.
<?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
:
orientation
=
"vertical"
>
<fragment
android
:
id
=
"@+id/detailFragment"
android
:
layout_width
=
"match_parent"
android
:
layout_height
=
"match_parent"
class
=
"com.example.android.rssfeed.DetailFragment"
/>
</LinearLayout>
11-2. L'activité DetailActivity▲
Créez une nouvelle activité nommée DetailActivity avec le code suivant :
package
com.example.android.rssfeed;
import
android.app.Activity;
import
android.content.res.Configuration;
import
android.os.Bundle;
import
android.widget.TextView;
public
class
DetailActivity extends
Activity {
public
static
final
String EXTRA_URL =
"url"
;
@Override
protected
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
// Need to check if Activity has been switched to landscape mode
// If yes, finished and go back to the start Activity
if
(
getResources
(
).getConfiguration
(
).orientation ==
Configuration.ORIENTATION_LANDSCAPE) {
finish
(
);
return
;
}
setContentView
(
R.layout.activity_detail);
Bundle extras =
getIntent
(
).getExtras
(
);
if
(
extras !=
null
) {
String s =
extras.getString
(
EXTRA_URL);
TextView view =
(
TextView) findViewById
(
R.id.detailsText);
view.setText
(
s);
}
}
}
Assurez-vous aussi d'enregistrer cette activité dans le fichier AndroidManifest.xml.
11-3. Modification de l'activité RssfeedActivity▲
Modifiez l'activité RssfeedActivity pour afficher l'activité DetailActivity au cas où l'autre fragment n'est pas présent dans la mise en page.
package
com.example.android.rssfeed;
import
android.app.Activity;
import
android.content.Intent;
import
android.os.Bundle;
import
android.view.Menu;
public
class
RssfeedActivity extends
Activity implements
MyListFragment.OnItemSelectedListener {
@Override
protected
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
setContentView
(
R.layout.activity_rssfeed);
}
@Override
public
void
onRssItemSelected
(
String link) {
DetailFragment fragment =
(
DetailFragment) getFragmentManager
(
)
.findFragmentById
(
R.id.detailFragment);
if
(
fragment !=
null
&&
fragment.isInLayout
(
)) {
fragment.setText
(
link);
}
else
{
Intent intent =
new
Intent
(
getApplicationContext
(
),
DetailActivity.class
);
intent.putExtra
(
DetailActivity.EXTRA_URL, link);
startActivity
(
intent);
}
}
}
11-4. Exécution▲
Lancez votre exemple. Si vous lancez votre application en mode portrait, vous ne devriez voir qu'un seul fragment. Utilisez le raccourci Ctrl+F11 pour changer l'orientation. En mode paysage, vous devriez voir les deux fragments. Si vous appuyez sur le bouton en mode portrait, une nouvelle activité DetailActivity est démarrée et montre la date courante. En mode paysage, vous voyez les deux fragments.
12. Exercice avec les fragments dynamiques▲
12-1. But▲
Modifiez l'exemple RssReader de manière à ce que des fragments dynamiques soient utilisés.
Une mise en page à plusieurs panneaux doit être utilisée dans le cas des écrans larges, par exemple pour les tablettes. Le point de basculement doit être de 600 dpi.
Implémentez la solution avec une activité et plusieurs fragments, supprimez l'activité DetailsActivity à la fin de cet exercice.
12-2. Utilisation d'un espace réservé pour les fragments▲
Remplacez le fragment statique dans le répertoire avec un FrameLayout comme espace réservé.
12-3. Utilisation du gestionnaire de fragments pour remplacer un fragment▲
Implémentez une solution de manière à ce que vous n'ayez qu'une seule activité et remplacez les fragments à la demande.
13. Liens et littérature▲
14. Remerciements▲
Vous pouvez retrouver l'article original ici : Using Fragments in Android - Tutorial. Nous remercions Lars Vogel qui nous a aimablement autorisés à traduire et héberger ses articles.
Nos remerciements à Phillipe DUVAL pour sa relecture orthographique.