Présentation De Fragments

Les fragments vous permettent de diviser vos activités en composants réutilisables entièrement encapsulés, chacun ayant son propre cycle de vie et son propre état.Chaque fragment est un module indépendant qui est faiblement couplé mais étroitement lié à l'activité dans laquelle il est ajouté. Les fragments peuvent contenir une interface utilisateur ou non, et peuvent être utilisés dans plusieurs activités. Les fragments qui encapsulent une interface utilisateur peuvent être agencés selon diverses combinaisons pour s'adapter à des interfaces utilisateur à plusieurs volets, mais également ajoutés, supprimés et échangés dans une activité en cours d'exécution pour aider à la création d'interfaces utilisateur dynamiques. Bien qu'il ne soit pas nécessaire de diviser vos activités (et leurs présentations correspondantes) en fragments, cela peut considérablement améliorer la flexibilité de votre interface utilisateur et faciliter l'adaptation de votre expérience utilisateur aux nouvelles configurations de périphériques. 

Remarque

Les fragments ont été introduits dans Android dans le cadre de l’Android 3.0.Version en nid d'abeille (API niveau 11). Ils sont désormais également disponibles dans la bibliothèque de support Android, notamment via AppCompatActivity, que nous utilisons actuellement.Si vous utilisez la bibliothèque de compatibilité, il est essentiel de vous assurer que toutes vos importations et références de fragments liées à Fragment utilisent uniquement les classes de la bibliothèque de support. Les packages de fragments de la bibliothèque native et de la bibliothèque de support sont étroitement liés, mais leurs classes ne sont pas interchangeables.

Créer de nouveaux fragments

Étendez la classe Fragment pour créer un nouveau fragment, définissez (éventuellement) l'interface utilisateur et implémentez les fonctionnalités qu'elle encapsule.Dans la plupart des cas, vous voudrez attribuer une interface utilisateur à votre fragment. Il est possible de créer unFragment qui n'inclut pas une interface utilisateur mais fournit plutôt un comportement en arrière-plan pour une activité. Ceci est exploré plus en détail plus tard dans ce chapitre.Si votre fragment nécessite une interface utilisateur, remplacez le gestionnaire onCreateView pour gonfler et renvoyer la hiérarchie de vues requise.

LISTING 3-6 : Fragment de code squelette 

import android.content.Context; import android.net.Uri; import android.os.Bundle;

import android.support.v4.app.Fragment; import android.view.LayoutInflater;

import android.view.View; import android.view.ViewGroup; public class MySkeletonFragment extends Fragment {

  public MySkeletonFragment() {

    // Required empty public constructor

  }

  @Override

  public View onCreateView(LayoutInflater inflater, ViewGroup container,

                           Bundle savedInstanceState) {

    // Inflate the layout for this fragment

    return inflater.inflate(R.layout.my_skeleton_fragment_layout,

                            container, false);

  }

} 

Vous pouvez créer une disposition dans le code à l'aide des groupes de vues de disposition; Toutefois, comme pour les activités, le moyen préféré pour concevoir des dispositions d'interface utilisateur de fragment consiste à gonfler une ressource XML.Contrairement aux activités, les fragments n’ont pas besoin d’être enregistrés dans votre manifeste. En effet, les fragments ne peuvent exister que s’ils sont intégrés à une activité, leur cycle de vie dépendant de celui de l’activité à laquelle ils ont été ajoutés.

Le cycle de vie des fragments

Les événements du cycle de vie d'un fragment reflètent ceux de son activité mère; Cependant, une fois que l'activité contenante est dans son état actif - reprise -, l'ajout ou la suppression d'un fragment affectera son cycle de vie de manière indépendante.Les fragments incluent une série de gestionnaires d'événements qui reflètent ceux de la classe d'activité. Ils sont déclenchés lorsque le fragment est créé, démarré, repris, mis en pause, arrêté et détruit. Les fragments incluent également un certain nombre de rappels supplémentaires indiquant l’attachement et le détachement du fragment au contexte de son parent, la création (et la destruction) de la hiérarchie de la vue du fragment et l’achèvement de la création de l’activité parent. La figure 3-4 résume le cycle de vie du fragment.Le code squelette du Listing 3-7 montre les stubs des gestionnaires de cycle de vie disponibles dans un fragment. Les commentaires dans chaque talon décrivent les actions à entreprendre lors de chaque événement de changement d'état. 

LISTING 3-7: Fragments de gestionnaires d’événements du cycle de vie, classe publique MySkeletonFragment

extends Fragment {

  // Required empty public constructor   public MySkeletonFragment() {}

  // Called when the Fragment is attached to its parent Activity.

  @Override

  public void onAttach(Context context) {

    super.onAttach(context);     // Get a reference to a Context representing     // the parent component.

  }

  // Called to do the initial creation of the Fragment.

  @Override

  public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    // Initialize the Fragment.

  }

  // Called once the Fragment has been created in order for it to   // create its user interface.

  @Override

  public View onCreateView(LayoutInflater inflater,

                           ViewGroup container,

                           Bundle savedInstanceState) {     // Create, or inflate the Fragment's UI, and return it.

    // If this Fragment has no UI then return null.

    return inflater.inflate(R.layout.my_skeleton_fragment_layout,

                            container, false);

  }

  // Called once the parent Activity and the Fragment's UI have   // been created.

  @Override

  public void onActivityCreated(Bundle savedInstanceState) {     super.onActivityCreated(savedInstanceState);

    // Complete the Fragment initialization – particularly anything

    // that requires the parent Activity to be initialized or the     // Fragment's view to be fully inflated.

  }

  // Called at the start of the visible lifetime.

  @Override   public void onStart() {     super.onStart();

    // Apply any required UI change now that the Fragment is visible.

  }

  // Called at the start of the active lifetime.

  @Override   public void onResume() {     super.onResume();

    // Resume any paused UI updates, threads, or processes required     // by the Fragment but suspended when it became inactive.

  }

  // Called at the end of the active lifetime.

  @Override   public void onPause() {     super.onPause();

    // Suspend UI updates, threads, or CPU intensive processes

    // that don't need to be updated when the Activity isn't     // the active foreground activity.

    // Persist all edits or state changes     // as after this call the process is likely to be killed.

  }

  // Called to save UI state changes at the   // end of the active lifecycle.

  @Override

  public void onSaveInstanceState(Bundle savedInstanceState) {     super.onSaveInstanceState(savedInstanceState);

    // Save UI state changes to the savedInstanceState.

    // This bundle will be passed to onCreate, onCreateView, and     // onCreateView if the parent Activity is killed and restarted.

  }

  // Called at the end of the visible lifetime.

  @Override   public void onStop() {     super.onStop();

    // Suspend remaining UI updates, threads, or processing     // that aren't required when the Fragment isn't visible.

  }

  // Called when the Fragment's View has been detached.

  @Override

  public void onDestroyView() {     super.onDestroyView();

    // Clean up resources related to the View.

  }

  // Called at the end of the full lifetime.

  @Override

  public void onDestroy() {     super.onDestroy();

    // Clean up any resources including ending threads,     // closing database connections etc.

  }

  // Called when the Fragment has been detached from its parent Activity.

  @Override

  public void onDetach() {     super.onDetach();

    // Clean up any references to the parent Activity

    // including references to its Views or classes. Typically setting     // those references to null.

  }

} 

Événements de cycle de vie spécifiques à un fragment

La plupart des événements du cycle de vie des fragments correspondent à leurs équivalents dans la classe d'activité, ce qui a été détaillé plus haut dans ce chapitre. Ceux qui restent sont spécifiques aux fragments et à la manière dont ils sont ajoutés à leur activité mère.  Attacher et détacher des fragments du contexte parent La vie entière de votre fragment commence quand il est lié au contexte de son parent et se termine quand il a été détaché. Ces événements sont représentés par les appels à onAttach et à onDetach, respectivement. L’événement onAttach est déclenché avant la création de l’UI du fragment, avant que le fragment lui-même ou son parent aient terminé leur initialisation. En général, l’événement onAttach est utilisé pour obtenir une référence au contexte du composant parent en vue de la préparation de tâches d’initialisation ultérieures.Le gestionnaire onDetach sera appelé si vous retirez un fragment de ses parents, ainsi que si le composant contenant votre fragment est détruit. Comme pour tout gestionnaire appelé après la mise en pause d’un fragment / activité, il est possible que onDetach ne soit pas appelé si le processus du composant parent est terminé avant la fin de son cycle de vie complet.  Création et destruction de fragments La durée de vie créée de votre fragment se situe entre le premier appel à onCreate et le dernier appel à onDestroy. Il n’est pas rare qu’un processus d’activité se termine sans que la méthode onDestroy correspondante soit appelée, de sorte qu’un fragment ne peut pas compter sur le déclenchement de son gestionnaire onDestroy.Comme pour les activités, vous devez utiliser la méthode onCreate pour initialiser votre fragment. C’est une bonne pratique de créer ici des objets de classe afin de s’assurer qu’ils n’ont été créés qu’une fois dans la vie du fragment.Notez que contrairement aux activités, l'interface utilisateur de fragment n'est pas gonflée dans le gestionnaire onCreate.  Création et destruction des interfaces utilisateur L’interface utilisateur d’un fragment est initialisée (et détruite) dans un nouvel ensemble de gestionnaires d’événements: onCreateView et onDestroyView, respectivement.Utilisez la méthode onCreateView pour initialiser votre fragment: gonflez l'interface utilisateur et obtenez des références (et liez des données) aux vues qu'il contient. Une fois que vous avez gonflé votre hiérarchie de vues, elle devrait être renvoyée par le gestionnaire: return inflater.inflate (R.layout.my_skeleton_fragment_layout, conteneur, false); Si votre fragment a besoin d'interagir avec l'interface utilisateur d'une activité parente, attendez que l'événement onActivityCreated ait été déclenché. Cela signifie que l'activité qui contient a terminé son initialisation et que son interface utilisateur a été entièrement construite.

États de fragment

Le destin d'un fragment est inextricablement lié à celui de la composante à laquelle il appartient. En conséquence, les transitions d'état de fragment sont étroitement liées aux transitions d'état d'activité correspondantes.Tout comme les activités, les fragments sont «actifs» lorsqu'ils appartiennent à une activité ciblée et au premier plan. Lorsqu'une activité est suspendue ou arrêtée, les fragments qu'elle contient sont également suspendus et arrêtés, ainsi que les fragments contenus dans une activité inactive. Lorsqu'une activité est finalement détruite, chaque fragment qu'il contient est également détruit.Comme le gestionnaire de mémoire Android ferme régulièrement les applications pour libérer des ressources, les fragments de ces activités sont également détruits.Bien que les activités et leurs fragments soient étroitement liés, l’un des avantages de l’utilisation de fragments pour composer l’interface utilisateur de votre activité est la possibilité d’ajouter ou de supprimer de manière dynamique des fragments d’une activité. En conséquence, chaque fragment peut progresser dans son cycle de vie complet, visible et actif, plusieurs fois au cours de la vie active de son activité mère.Quel que soit le déclencheur de la transition d’un fragment au cours de son cycle de vie, la gestion de ses transitions d’état est essentielle pour garantir une expérience utilisateur transparente. Il ne doit y avoir aucune différence entre un fragment qui passe d’un état détaché, en pause, arrêté ou inactif à un état actif. Il est donc important de sauvegarder tous les états de l’UI et de conserver toutes les données lorsqu'un fragment est en pause ou arrêté. Comme une activité, lorsqu'un fragment redevient actif, il devrait restaurer cet état enregistré.

Présentation du gestionnaire de fragments

L'introduction de l'activité FragEach inclut un gestionnaire de fragments pour gérer les fragments qu'il contient. Comme nous utilisons la bibliothèque de support, nous accéderons au gestionnaire de fragments à l’aide de la méthode getSupportFragmentManager: FragmentManager fragmentManager = getSupportFragmentManager (); Le Gestionnaire de fragments fournit les méthodes utilisées pour accéder aux fragments actuellement ajoutés à l'activité et pour effectuer des transactions de fragments afin d'ajouter, de supprimer et de remplacer des fragments.gestionnaire de gestion

Ajouter des fragments aux activités

Le moyen le plus simple d’ajouter un fragment à une activité est de l’inclure dans la présentation de l’activité à l’aide de la balise fragment, comme indiqué dans le Listing 3-8. LISTING 3-8: Ajouter des fragments à des activités à l'aide de dispositions XML

< ?xml version="1.0" encoding="utf-8"? >

< LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  android:orientation="horizontal"   android:layout_width="match_parent"   android:layout_height="match_parent">

  <fragment android:name="com.professionalandroid.apps.MyListFragment"

    android:id="@+id/my_list_fragment"     android:layout_width="wrap_content"     android:layout_height="match_parent"

    android:layout_weight="1"

  />

  <fragment android:name="com.professionalandroid.apps.DetailFragment"

    android:id="@+id/details_fragment"     android:layout_width="wrap_content"     android:layout_height="match_parent"

    android:layout_weight="3"

  />

< /LinearLayout >

Une fois que le fragment a été gonflé, il devient un groupe de vues au sein de la hiérarchie des vues, affichant et gérant son interface utilisateur au sein de l'activité.Cette technique fonctionne bien lorsque vous utilisez Fragments pour définir un ensemble de dispositions statiques basées sur différentes tailles d'écran. Si vous envisagez de modifier dynamiquement vos présentations en ajoutant, en supprimant et en remplaçant des fragments au moment de l'exécution, une meilleure approche consiste à créer des dispositions utilisant des vues de conteneur dans lesquelles des fragments peuvent être placés au moment de l'exécution, en fonction de l'état actuel de l'application. La liste 3-9 montre un extrait de code XML que vous pouvez utiliser pour prendre en charge cette approche.LISTING 3-9: Spécifier des mises en page de fragments à l'aide de vues de conteneur

< ?xml version="1.0" encoding="utf-8"? >

< LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  android:orientation="horizontal"   android:layout_width="match_parent"   android:layout_height="match_parent">

  <FrameLayout

    android:id="@+id/list_container"     android:layout_width="wrap_content"     android:layout_height="match_parent"

    android:layout_weight="1"

  />

  <FrameLayout

    android:id="@+id/details_container"     android:layout_width="wrap_content"     android:layout_height="match_parent"

    android:layout_weight="3"

  />

< /LinearLayout >

Vous devez ensuite créer et ajouter les fragments correspondants aux conteneurs parents appropriés de votre activité à l'aide de transactions de fragments, comme décrit dans la section suivante.

Utiliser des transactions de fragment

Les transactions de fragments sont utilisées pour ajouter, supprimer et remplacer des fragments dans une activité au moment de l'exécution. À l'aide de Fragment Transactions, vous pouvez dynamiser vos mises en page, c'est-à-dire qu'elles s'adapteront et changeront en fonction des interactions de l'utilisateur et de l'état de l'application.Chaque transaction de fragment peut inclure toute combinaison d’actions prises en charge, notamment l’ajout, la suppression ou le remplacement de fragments. Ils prennent également en charge la spécification des animations de transition à afficher et si une transaction doit être ajoutée à la pile arrière.Une nouvelle transaction de fragment est créée à l'aide de la méthode beginTransaction à partir du gestionnaire de fragments. Modifiez la présentation à l'aide des méthodes d'ajout, de suppression et de remplacement, si nécessaire, avant de définir les animations à afficher et de définir le comportement de pile arrière approprié. Lorsque vous êtes prêt à exécuter la modification, appelez commit pour ajouter la transaction à la file d'attente de l'interface utilisateur de manière asynchrone, ou commitNow pour bloquer jusqu'à ce que la transaction soit complètement terminée: FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction (); // Ajouter, supprimer et / ou remplacer des fragments.// Spécifie les animations.// Ajouter à la pile de retour si nécessaire. fragmentTransaction.commitNow ();CommitNow est l'alternative par défaut, mais il n'est disponible que si la transaction en cours n'est pas ajoutée à la pile arrière. Cette option, ainsi que chaque type de transaction et les options associées, est explorée dans les sections suivantes.

Ajouter, supprimer et remplacer des fragments

Lors de l'ajout d'un nouveau fragment d'interface utilisateur, commencez par le créer et transmettez la nouvelle instance de fragment, ainsi que le conteneur View dans lequel le fragment sera placé, à la méthode d'ajout de votre transaction de fragment. Vous pouvez éventuellement spécifier une balise pouvant être utilisée ultérieurement pour rechercher le fragment lorsque vous utilisez la méthode findFragmentByTag: chaîne statique finale MY_FRAGMENT_TAG = "detail_fragment"; Avec la balise définie, vous pouvez utiliser la méthode add comme suit: FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction (); fragmentTransaction.add (R.id.details_container, new DetailFragment (),                        MY_FRAGMENT_TAG); fragmentTransaction.commitNow (); Pour supprimer un fragment, vous devez d’abord trouver une référence à celui-ci, en utilisant généralement les méthodes findFragmentById ou findFragmentByTag du gestionnaire de fragments. Ensuite, passez l'instance de Fragment trouvée en tant que paramètre à la méthode de suppression d'une transaction de fragment: FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction ();Fragment fragment = fragmentManager.findFragmentByTag (MY_FRAGMENT_TAG);fragmentTransaction.remove (fragment); fragmentTransaction.commitNow (); Vous pouvez également remplacer un fragment par un autre. A l'aide de la méthode replace, spécifiez l'ID de conteneur contenant le fragment à remplacer, le fragment avec lequel le remplacer, et (éventuellement) une balise permettant d'identifier le fragment nouvellement inséré: FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction ();fragmentTransaction.replace (R.id.details_container,                            new DetailFragment (selected_index),                            MY_FRAGMENT_TAG); fragmentTransaction.commitNow () 

Fragments et changements de configuration

Afin de maintenir un état cohérent de l'interface utilisateur entre les modifications de configuration, tous les fragments ajoutés à votre interface seront automatiquement restaurés lorsqu'une activité est recréée à la suite d'un changement d'orientation ou d'une fin inattendue.Cela est particulièrement important si vous remplissez votre présentation Activité avec des fragments dans le gestionnaire onCreate. Dans ce cas, vous devez vérifier si les fragments ont déjà été ajoutés pour éviter de créer plusieurs copies.Vous pouvez le faire soit en recherchant des fragments avant de les ajouter, soit s’il s’agit d’un redémarrage de l’activité en vérifiant si la fonction savedInstanceState est null:

protected void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);   setContentView(R.layout.activity_main);   if (savedInstanceState == null) {

    // Create and add your Fragments.

  } else {     // Get references to Fragments that have already been restored.

 

} 

Utilisation du gestionnaire de fragments pour rechercher des fragments

Pour rechercher des fragments dans votre activité, utilisez la méthode findFragmentById du gestionnaire de fragments. Si vous avez ajouté votre fragment à la structure d’activité en XML, vous pouvez utiliser l’identifiant de la ressource du fragment: MyFragment myFragment =  (MyFragment) fragmentManager.findFragmentById (R.id.MyFragment); Si vous avez ajouté un fragment à l'aide d'une transaction de fragment, vous pouvez plutôt spécifier l'identificateur de ressource du conteneur. La vue à laquelle vous avez ajouté le fragment que vous souhaitez trouver: DetailFragment detailFragment =  (DetailFragment) fragmentManager.findFragmentById (R.id.details_container); Vous pouvez également utiliser la méthode findFragmentByTag pour rechercher le fragment à l'aide de la balise que vous avez spécifiée dans la transaction de fragment: DetailFragment detailFragment =  (DetailFragment) fragmentManager.findFragmentByTag (MY_FRAGMENT_TAG); Plus loin dans ce chapitre, nous vous présenterons des fragments qui ne contiennent pas d’UI. La méthode findFragmentByTag est essentielle pour interagir avec ces fragments. Comme ils ne font pas partie de la hiérarchie de la vue Activité, ils n’ont pas d’identificateur de ressource ni d’identificateur de ressource conteneur à transmettre à la méthode findFragmentById.

Remplir des mises en page d'activités dynamiques avec des fragments

Si vous modifiez de manière dynamique la composition et la présentation de vos fragments au moment de l'exécution, il est recommandé de définir uniquement les conteneurs parents au sein de votre disposition XML et de le renseigner exclusivement à l'aide de Fragment Transactions au moment de l'exécution afin de garantir la cohérence lorsque la configuration change. rotation) entraînent la recréation de l'interface utilisateur, comme décrit précédemment. La liste 3-10 montre le code squelette utilisé pour remplir la présentation d’une activité avec des fragments au moment de l’exécution; dans ce cas, nous vérifions l'existence d'un fragment avant de créer et d'ajouter un nouveau fragment.LISTING 3-10: Remplir des mises en page de fragments à l'aide de vues de conteneurs

public void onCreate(Bundle savedInstanceState) {   super.onCreate(savedInstanceState);

  // Inflate the layout containing the Fragment containers   setContentView(R.layout.fragment_container_layout);

  FragmentManager fragmentManager = getSupportFragmentManager();

  // Check to see if the Fragment containers have been populated   // with Fragment instances. If not, create and populate the layout.

  DetailFragment detailsFragment =

    (DetailFragment) fragmentManager.findFragmentById(R.id.details_container);

  if (detailsFragment == null) {

     FragmentTransaction ft = fragmentManager.beginTransaction();      ft.add(R.id.details_container, new DetailFragment());      ft.add(R.id.list_container, new MyListFragment());

     ft.commitNow();

   }

}

Pour garantir une expérience utilisateur cohérente, Android conserve la mise en page Fragment et la pile arrière associée lorsqu'une activité est redémarrée en raison d'un changement de configuration.Pour la même raison, lors de la création de présentations alternatives pour les modifications de configuration au moment de l’exécution, il est recommandé d’inclure tous les conteneurs de vues impliqués dans des transactions dans toutes les variantes de présentation. Sinon, le gestionnaire de fragments tentera de restaurer les fragments dans des conteneurs qui n'existent pas dans la nouvelle présentation.Pour supprimer un conteneur Fragment dans une mise en page d'orientation donnée, il suffit de marquer son attribut de visibilité comme indiqué dans la définition de votre mise en page, comme indiqué dans le Listing 3-11.

LISTING 3-11: Cacher des fragments dans les variations de disposition

< ?xml version="1.0" encoding="utf-8"? >

< LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  android:orientation="horizontal"   android:layout_width="match_parent"   android:layout_height="match_parent">

  <FrameLayout

    android:id="@+id/list_container"     android:layout_width="wrap_content"     android:layout_height="match_parent"

    android:layout_weight="1"

  />

  <FrameLayout

    android:id="@+id/details_container"     android:layout_width="wrap_content"     android:layout_height="match_parent"

    android:layout_weight="3"     android:visibility="gone"

  />

< /LinearLayout >

Fragments et la pile de dos

Nous avons décrit le concept de piles d’activités, l’empilement logique d’activités qui ne sont plus visibles, permettant aux utilisateurs de revenir aux écrans précédents à l’aide du bouton Précédent.Les fragments vous permettent de créer des présentations d'activité dynamiques pouvant être modifiées pour présenter des modifications significatives dans les interfaces utilisateur. Dans certains cas, ces modifications peuvent être considérées comme un nouvel écran. Dans ce cas, un utilisateur peut raisonnablement s’attendre à ce que le bouton Précédent revienne à la présentation précédente. Cela implique l'inversion des transactions de fragments précédemment exécutées.Android fournit une technique pratique pour fournir cette fonctionnalité. Pour ajouter la transaction de fragment à la pile arrière, appelez addToBackStack sur une transaction de fragment avant d'appeler commit. Il est important de noter que commitNow ne peut pas être utilisé lors de l'application de transactions de fragment ajoutées à la pile arrière. Dans l'extrait de code suivant, nous avons une présentation qui affiche la liste ou la vue détaillée. Cette transaction supprimera le fragment de liste, ajoutera le fragment de détail et ajoutera la modification à la pile arrière:

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

// Find and remove the list Fragment

Fragment fragment = fragmentManager.findFragmentById(R.id.ui_container); fragmentTransaction.remove(fragment);

// Create and add the detail Fragment fragmentTransaction.add(R.id.ui_container, new DetailFragment());

// Add the Fragment Transaction to the backstack and commit the change.

fragmentTransaction.addToBackStack(BACKSTACK_TAG); fragmentTransaction.commit();

Appuyez sur le bouton Précédent pour inverser la transaction de fragment précédente et ramener l'interface utilisateur à la présentation précédente.Lorsque la transaction de fragment précédente est validée, le fragment de liste est arrêté, détaché et placé dans la pile arrière au lieu d'être simplement détruit. Si la transaction est inversée, le fragment de détail est détruit et le fragment de liste est redémarré et rattaché à l'activité.

Animation de transactions de fragments

Pour appliquer l'une des animations de transition par défaut, utilisez la méthode setTransition sur toute transaction de fragment, en transmettant l'une des constantes FragmentTransaction.TRANSIT_FRAGMENT_ *: fragementTransaction.setTransition (FragmentTransaction.TRANSIT_FRAGMENT_OPEN); Vous pouvez également appliquer des animations personnalisées aux transactions de fragment en utilisant la méthode setCustomAnimations, avant d'appeler les méthodes d'ajout ou de suppression de votre transaction de fragment.Cette méthode accepte deux ressources XML Object Animator: une pour les fragments ajoutés à la présentation et une autre pour les fragments en cours de suppression: fragmentTransaction.setCustomAnimations (android.R.anim.fade_in, android.R.anim.fade_out); C’est un moyen particulièrement utile d’ajouter des transitions dynamiques et transparentes lorsque vous remplacezFragments dans votre mise en page. Vous trouverez plus de détails sur la création d’animateur et deRessources d'animation dans le chapitre 14, «Personnalisation avancée de votre interface utilisateur». 

Communiquer entre fragments et activités

Lorsque votre fragment a besoin de partager des événements avec son activité hôte (par exemple, en signalant des sélections d'interface utilisateur), il est recommandé de créer une interface de rappel dans le fragment qu'une activité hôte doit implémenter.Le Listing 3-12 montre un extrait de code issu d'une classe Fragment qui définit une interface d'écoute d'événement publique. Le gestionnaire onAttach est remplacé pour obtenir une référence à l'activité hôte, confirmant qu'il implémente l'interface requise. Le gestionnaire onDetach définit notre référence sur null et la méthode onButtonPressed est utilisée comme exemple d'espace réservé qui appelle la méthode d'interface sur notre activité parent. LISTING 3-12: Définition des interfaces de rappel d'événement de fragment, classe publique

MySkeletonFragment extends Fragment {

  public interface OnFragmentInteractionListener {

    // TODO Update argument type and name     void onFragmentInteraction(Uri uri);   }   private OnFragmentInteractionListener mListener;   public MySkeletonFragment() {}

  @Override

  public View onCreateView(LayoutInflater inflater, ViewGroup container,

                           Bundle savedInstanceState) {

    // Inflate the layout for this fragment

    return inflater.inflate(R.layout.my_skeleton_fragment_layout,

                            container, false);   }

  @Override

  public void onAttach(Context context) {

    super.onAttach(context);

    if (context instanceof OnFragmentInteractionListener) {       mListener = (OnFragmentInteractionListener) context;

    } else {

      throw new RuntimeException(context.toString()

                  + " must implement OnFragmentInteractionListener");

    }

  }

  @Override

  public void onDetach() {     super.onDetach();     mListener = null;

  }

  public void onButtonPressed(Uri uri) {

    if (mListener != null) {

      mListener.onFragmentInteraction(uri);

    }

  }

}

Vous pouvez également utiliser la méthode getContext dans n’importe quel fragment pour renvoyer une référence au contexte du composant dans lequel il est incorporé.Bien que les fragments puissent communiquer entre eux à l’aide du gestionnaire de fragments de l’activité hôte, il est généralement considéré comme une meilleure pratique d’utiliser l’Activité en tant qu’intermédiaire. Cela permet aux fragments d'être aussi indépendants et couplés que possible, avec la responsabilité de décider de la manière dont un événement d'un fragment doit affecter l'interface utilisateur globale tombant dans l'activité hôte.

Fragments sans interfaces utilisateur

Dans la plupart des cas, les fragments sont utilisés pour encapsuler des composants modulaires de l'interface utilisateur; Toutefois, vous pouvez également créer un fragment sans interface utilisateur afin de fournir un comportement en arrière-plan qui persiste lors des redémarrages d'activité provoqué par des modifications de la configuration.Vous pouvez choisir qu'un fragment actif conserve son instance actuelle lorsque son activité parent est recréée à l'aide de la méthode setRetainInstance. Après avoir appelé cette méthode, le cycle de vie du fragment va changer.Plutôt que d'être détruite et recréée avec son activité parent, la même instance de fragment est conservée lorsque l'activité redémarre. Il recevra l'événement onDetach lorsque l'activité parent sera détruite, suivi des événements onAttach, onCreateView et onActivityCreated lors de l'instanciation de la nouvelle activité parent. L'extrait suivant montre le code squelette d'un fragment sans interface utilisateur: publict Interfaces utilisateur 

class WorkerFragment extends Fragment {   public final static String MY_FRAGMENT_TAG = "my_fragment";

  @Override

  public void onAttach(Context context) {     super.onAttach(context);

    // Get a type-safe reference to the parent context.

  }

  @Override

  public void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);

    // Create ongoing threads and tasks.

  }

@Override

  public void onActivityCreated(Bundle savedInstanceState) {     super.onActivityCreated(savedInstanceState);

    // Initiate worker threads and tasks.

  }

}

Pour ajouter ce fragment à votre activité, créez une nouvelle transaction de fragment en spécifiant une balise à utiliser pour l'identifier. Parce que le fragment n'a pas d'interface utilisateur, il ne doit pas être associé à une vue conteneur ni ajouté à la pile arrière: 

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.add(new WorkerFragment(), WorkerFragment.MY_FRAGMENT_TAG); fragmentTransaction.commitNow();

Utilisez le findFragmentByTag du gestionnaire de fragments pour trouver une référence plus tard:

WorkerFragment workerFragment

  = (WorkerFragment)fragmentManager

     .findFragmentByTag(WorkerFragment.MY_FRAGMENT_TAG);