66 votes

Variables membres vs setArguments dans Fragments

J'ai remarqué que dans la référence Android pour Fragments (notamment DialogFragment ) qu'ils font deux ou trois choses différentes de ce que j'attendais :

1). Utilisez public static foo newInstance() plutôt qu'un constructeur.
2). Passez des valeurs à onCreateDialog en utilisant setArguments plutôt que des variables membres.

J'ai lu que newInstance semble être préférable lorsqu'on utilise la réflexion. Cependant, je ne comprends vraiment pas pourquoi ils passent des paramètres via un bundle. J'aurais pensé que l'utilisation de variables membres serait plus sûre (ne pas utiliser une chaîne pour aller chercher dans une carte) et aurait moins de surcharge.

Des idées ?

49voto

Philipp Reichart Points 10371

Je suis également tombé sur ce sujet et j'ai trouvé quelques avantages à utiliser ces arguments Bundle sur les champs d'instance :

  • Si c'est dans un Bundle le système Android le sait et peut créer et détruire votre Fragment (en utilisant le constructeur obligatoire sans paramètre/par défaut et les méthodes habituelles du cycle de vie), et il suffit de transmettre à nouveau le faisceau d'arguments. De cette façon, aucun argument ne se perd lors d'une destruction de mémoire ou lors d'un éventuel changement d'orientation (cela m'arrive souvent lors du premier déploiement sur un appareil réel après un développement dans un émulateur qui tourne moins).

  • Vous pouvez simplement passer les extras Bundle d'un Activity en l'état à un Fragment intégré dans la mise en page ; par exemple, je l'utilise souvent lorsque j'ai une Activity qui affiche un Fragment "fullscreen" et a besoin d'une identification (ou ContentProvider URI) pour savoir ce qu'il faut afficher/faire. Il m'arrive même d'ajouter des éléments supplémentaires à un Bundle (ou une copie) avant de le transmettre, par ex.

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
    
      if (savedInstanceState == null) { // not a re-creation
        final Bundle args = new Bundle(getIntent().getExtras());
        args.putInt(CoverImageFragment.BACKGROUND_RESOURCE, android.R.color.black);
        final Fragment fragment = CoverImageFragment.newInstance(args);
        getSupportFragmentManager()
          .beginTransaction()
          .add(android.R.id.content, fragment)
          .commit();
      }
    }
  • Il maintient la manière de développer un Fragment proche de celle d'un Activity c'est-à-dire Bundle comme "paramètres d'entrée, sans exception".

Quant aux inconvénients que vous avez mentionnés :

  • Je pense que les frais généraux sont minimes, car il est fort probable que vous ne fassiez pas de requêtes sur le fichier Bundle dans une boucle serrée, donc sortir les données de l'argument une fois en onCreate() , onViewCreate() etc. n'est pas si mal.

  • Pour la sécurité du type, Bundle a tous les différents getXXXX() et même des surcharges pour fournir une valeur par défaut si un élément est manquant/optionnel :)

Quant à la newInstance() je les considère comme un moyen facile d'encapsuler les méthodes de new et setArguments() appelle à mon Fragment Je fournis parfois un supplément MyFragment newInstance(String singleIdOfWhatToDisplay) qui crée à la fois le Bundle et Fragment en une seule fois et renvoie un fichier prêt à l'emploi Fragment instance.

19voto

rmirabelle Points 822

J'ai trouvé que c'était un problème TRÈS déroutant (l'un des nombreux qui jonchent le paysage Android).

setArguments() est une solution de contournement pour le besoin très peu utile d'Android d'avoir un constructeur sans paramètre disponible pour les fragments.

Ma confusion est venue par vagues. D'abord, les méthodes que vous remplacez naturellement dans vos Fragment (par exemple onCreate , onCreateView ) reçoivent un Bundle qui représente le savedInstanceState de votre Fragment . Cet état d'instance a apparemment NOTHING quoi que ce soit à faire avec les valeurs que vous stockez par l'intermédiaire de setArguments() et récupérer via getArguments() . Les deux utilisent un Bundle les deux Bundles sont susceptibles d'être accédées au sein de la même méthode surchargée, elles n'ont rien à voir l'une avec l'autre.

Deuxièmement, il n'est pas clair comment Android utilise setArguments() . Android appelle votre constructeur sans paramètre pour reconstruire votre Fragment sur la rotation, mais apparemment, ALSO appellera n'importe qui setArguments() a été appelée pour la dernière fois lorsque la méthode Fragment a été construit.

Huh ????

Incroyable, mais vrai. Toute cette création Bundles avec setArguments() La folie existe pour compenser le besoin d'un système sans paramètre. Fragment constructeur.

En bref, j'utilise la méthode statique newInstance pour créer mon Fragment .

public MyFragment() {
    //satisfy Android
}

public static MyFragment newInstance(long record_id) {
    Log.d("MyFragment", "Putting " + record_id + " into newInstance");
    MyFragment f = new MyFragment();
    Bundle args = new Bundle();
    args.putLong("record_id", record_id);
    f.setArguments(args);
    return f;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    /**
     * Perform an immediate check of arguments,
     * which ARE NOT the same as the bundle used
     * for saved instance state.
     */
    Bundle args = getArguments();
    if(args != null) {
        record_id = args.getLong("record_id");
        Log.d("MyFragment", "found record_id of " + String.valueOf(record_id));
    }
    if(savedInstanceState != null) {
        //now do something with savedInstanceState
    }
}

9voto

WayneJ Points 257

Je suis assez novice en matière de programmation Android, mais voici comment je comprends actuellement le problème :

Le constructeur pour Fragments ne peut pas n'ont pas de paramètres. Lorsque votre activité est en pause, votre Fragment peut être libéré. Avant la reprise de votre activité, le système crée une nouvelle version de votre Fragment en appelant le constructeur. Si un constructeur autre que celui par défaut est utilisé, comment Android est-il censé savoir quels sont les types et les valeurs des arguments du constructeur de vos fragments ?

Je ne crois pas que cette liasse soit libérée. Le paquet est conservé précisément pour qu'il puisse être retransmis à votre fragment après qu'il ait été recréé avec le constructeur par défaut.

Philipp Reichart y a fait allusion dans son billet (en fait, il a fait plus qu'y faire allusion).

2voto

havexz Points 6707

Je souhaite simplement ajouter un autre inconvénient aux arguments, à savoir que vous devez créer des fragments de manière dynamique. Comme arguments ne fonctionne pas très bien si vous créez à partir du xml. Et je déteste vraiment cela.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X