J'ai vu deux pratiques générales pour instancier un nouveau fragment dans une application:
Fragment newFragment = new MyFragment();
et
Fragment newFragment = MyFragment.newInstance();
La deuxième option utilise une méthode statique newInstance()
et contient généralement la méthode suivante.
public static Fragment newInstance()
{
MyFragment myFragment = new MyFragment();
return myFragment;
}
Au début, je pensais que le principal avantage était le fait que je pouvais surcharger la méthode newInstance () pour donner de la flexibilité lors de la création de nouvelles instances d'un fragment - mais je pouvais également le faire en créant un constructeur surchargé pour le fragment.
Ai-je oublié quelque chose?
Quels sont les avantages d'une approche par rapport à l'autre? Ou s'agit-il simplement d'une bonne pratique?
android
android-fragments
Graham Smith
la source
la source
Réponses:
Si Android décide de recréer votre fragment plus tard, il appellera le constructeur sans argument de votre fragment. Surcharger le constructeur n'est donc pas une solution.
Cela étant dit, la façon de transmettre des éléments à votre fragment afin qu'ils soient disponibles après la recréation d'un fragment par Android est de passer un bundle à la
setArguments
méthode.Ainsi, par exemple, si nous voulions passer un entier au fragment, nous utiliserions quelque chose comme:
Et plus tard dans le fragment,
onCreate()
vous pouvez accéder à cet entier en utilisant:Ce bundle sera disponible même si le fragment est en quelque sorte recréé par Android.
Notez également:
setArguments
ne peut être appelé que lorsque le fragment est attaché à l'activité.Cette approche est également documentée dans la référence du développeur Android: https://developer.android.com/reference/android/app/Fragment.html
la source
Le seul avantage à utiliser le
newInstance()
que je vois sont les suivants:Vous aurez un seul endroit où tous les arguments utilisés par le fragment pourraient être regroupés et vous n'avez pas à écrire le code ci-dessous chaque fois que vous instanciez un fragment.
C'est un bon moyen de dire aux autres classes quels arguments il attend pour fonctionner fidèlement (bien que vous devriez être capable de gérer les cas si aucun argument n'est groupé dans l'instance de fragment).
Donc, mon avis est que l'utilisation d'une statique
newInstance()
pour instancier un fragment est une bonne pratique.la source
Il existe également un autre moyen:
la source
instantiate()
Creates a new instance of a Fragment with the given class name. This is the same as calling its empty constructor.
Alors que @yydl donne une raison convaincante pour laquelle la
newInstance
méthode est meilleure:il est tout à fait possible d'utiliser un constructeur . Pour voir pourquoi cela est, nous devons d'abord voir pourquoi la solution de contournement ci-dessus est utilisée par Android.
Avant qu'un fragment puisse être utilisé, une instance est nécessaire. Android appelle
YourFragment()
(le constructeur sans arguments ) pour construire une instance du fragment. Ici, tout constructeur surchargé que vous écrivez sera ignoré, car Android ne peut pas savoir lequel utiliser.Pendant la durée de vie d'une activité, le fragment est créé comme ci-dessus et détruit plusieurs fois par Android. Cela signifie que si vous placez des données dans l'objet fragment lui-même, elles seront perdues une fois le fragment détruit.
Pour contourner ce problème, Android vous demande de stocker les données à l'aide d'un
Bundle
(appelsetArguments()
), auquel vous pourrez ensuite accéderYourFragment
. Les argumentsbundle
sont protégés par Android et sont donc garantis persistants .Une façon de définir cet ensemble consiste à utiliser une
newInstance
méthode statique :Cependant, un constructeur:
peut faire exactement la même chose que la
newInstance
méthode.Naturellement, cela échouerait et c'est l'une des raisons pour lesquelles Android souhaite que vous utilisiez la
newInstance
méthode:Pour plus d'explications, voici la classe de fragments d'Android:
Notez qu'Android demande que les arguments ne soient définis qu'à la construction et garantit qu'ils seront conservés.
EDIT : Comme indiqué dans les commentaires de @JHH, si vous fournissez un constructeur personnalisé qui nécessite des arguments, alors Java ne fournira pas votre fragment avec un constructeur par défaut sans argument . Donc, cela vous obligerait à définir un constructeur sans argument , qui est du code que vous pourriez éviter avec la
newInstance
méthode d'usine.EDIT : Android ne permet plus d'utiliser un constructeur surchargé pour les fragments. Vous devez utiliser la
newInstance
méthode.la source
Je ne suis pas d' accord avec la réponse de yydi disant:
Je pense que c'est une solution et une bonne, c'est exactement la raison pour laquelle elle a été développée par le langage Java Core.
Il est vrai que le système Android peut détruire et recréer votre
Fragment
. Vous pouvez donc faire ceci:Il vous permettra de tirer
someInt
degetArguments()
ce dernier, même s'il aFragment
été recréé par le système. C'est une solution plus élégante que lestatic
constructeur.Pour moi, les
static
constructeurs sont inutiles et ne doivent pas être utilisés. De plus, ils vous limiteront si à l'avenir vous souhaitez étendre celaFragment
et ajouter plus de fonctionnalités au constructeur. Avec lestatic
constructeur, vous ne pouvez pas faire cela.Mise à jour:
Android a ajouté une inspection qui marque tous les constructeurs non par défaut avec une erreur.
Je recommande de le désactiver, pour les raisons mentionnées ci-dessus.
la source
Certains Kotlin code:
Et vous pouvez obtenir des arguments avec ceci:
la source
La meilleure pratique pour instance de fragments avec des arguments dans Android est d'avoir une méthode d'usine statique dans votre fragment.
Vous devez éviter de définir vos champs avec l'instance d'un fragment. Parce que chaque fois que le système Android recrée votre fragment, s'il estime que le système a besoin de plus de mémoire, il recréera votre fragment en utilisant un constructeur sans arguments.
Vous pouvez trouver plus d'informations sur les meilleures pratiques pour instancier des fragments avec des arguments ici.
la source
Étant donné que les questions sur les meilleures pratiques, j'ajouterais, cette très bonne idée d'utiliser une approche hybride pour créer des fragments lorsque vous travaillez avec certains services Web REST
Nous ne pouvons pas passer des objets complexes, par exemple certains modèles utilisateur, pour le cas de l'affichage d'un fragment utilisateur
Mais ce que nous pouvons faire, c'est archiver
onCreate
cet utilisateur! = Null et sinon - l'amener de la couche de données, sinon - utiliser l'existant.De cette façon, nous gagnons à la fois la capacité de recréer par userId en cas de recréation de fragments par Android et l'accrochage pour les actions de l'utilisateur, ainsi que la capacité de créer des fragments en se tenant à l'objet lui-même ou uniquement son identifiant
Quelque chose aime ça:
la source
User user = /*...*/
mettez l'utilisateur dans le bundle:Bundle bundle = new Bundle(); bundle.putParcelable("some_user", user);
et récupérez l'utilisateur à partir des arguments:User user = getArguments().getParcelable("some_user");
l'objet doit être implémenter l'interface Parcelable. linkutiliser ce code 100% résoudre votre problème
entrez ce code dans firstFragment
cet échantillon envoie des données booléennes
et dans SecendFragment
code heureux
la source
La meilleure façon d'instancier le fragment est d'utiliser la méthode Fragment.instantiate par défaut ou de créer la méthode d'usine pour instancier le fragment
.
la source
Je suis ici dernièrement. Mais quelque chose que je viens de savoir pourrait vous aider un peu.
Si vous utilisez Java, il n'y a rien à changer. Mais pour les développeurs de kotlin, voici un extrait suivant, je pense, qui peut faire de vous un sous-sol sur lequel fonctionner:
Codage heureux.
la source
setArguments()
est inutile. Cela ne fait qu'amener un gâchis.la source
onViewCreated
portée. C'est pratique, je suppose, de nombreuses façons de faire la même chose. C'est aussi un moyen facile de vérifier les mises à jour effectuées par l'utilisateur (comparer les bundles degetArguments
et le bundle deonSaveInstanceState
)getArguments
trucs. Qu'en est-il de laonViewCreated
portée ... Nous pouvons restaurer le paquet d'état là-bas. Mais je préfère juste faireonCreateView
léger et rapide et faire toutes les initialisations lourdes à l'intérieur d'unonActivityCreated
parce queFragment.getActivity()
j'aime parfois revenirnull
et à cause desonAttach()
changements dans la nouvelle version de l'API 23.set
etget
Arguments
danssaveInstanceState
. Vous faites essentiellement la même chose que ce qui se fait "sous le capot"saveInstanceState
est "sous le capot". Et l'utilisation deArguments
est une duplication de fonctionnalités qui vous fait vérifier: d'abord lesArguments
valeurs puis lessaveInstanceState
valeurs. Parce que vous devez utilisersaveInstanceState
n'importe quel moyen. Qu'en est-ilArguments
... ils ne sont pas nécessaires.Je crois que j'ai une solution beaucoup plus simple pour cela.
la source