web-dev-qa-db-fra.com

Créer un fragment: constructeur vs newInstance ()

Je me suis récemment fatigué de devoir constamment connaître les clés String pour passer des arguments en Bundles lors de la création de ma Fragments. J'ai donc décidé de créer des constructeurs pour ma Fragments qui prendraient les paramètres que je voulais définir et de placer ces variables dans la Bundles avec les clés String correctes, éliminant ainsi le besoin d'autres Fragments et Activities ayant besoin de connaître ces clés.

public ImageRotatorFragment() {
    super();
    Log.v(TAG, "ImageRotatorFragment()");
}

public ImageRotatorFragment(int imageResourceId) {
    Log.v(TAG, "ImageRotatorFragment(int imageResourceId)");

    // Get arguments passed in, if any
    Bundle args = getArguments();
    if (args == null) {
        args = new Bundle();
    }
    // Add parameters to the argument bundle
    args.putInt(KEY_ARG_IMAGE_RES_ID, imageResourceId);
    setArguments(args);
}

Et puis je tire ces arguments comme d'habitude.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.v(TAG, "onCreate");

    // Set incoming parameters
    Bundle args = getArguments();
    if (args != null) {
        mImageResourceId = args.getInt(KEY_ARG_IMAGE_RES_ID, StaticData.getImageIds()[0]);
    }
    else {
        // Default image resource to the first image
        mImageResourceId = StaticData.getImageIds()[0];
    }
}

Cependant, Lint a contesté cette affirmation en disant de ne pas avoir de sous-classes de Fragment avec des constructeurs avec d'autres paramètres, ce qui m'oblige à utiliser @SuppressLint("ValidFragment") pour même exécuter l'application. Le fait est que ce code fonctionne parfaitement. Je peux utiliser ImageRotatorFragment(int imageResourceId) ou la méthode old school ImageRotatorFragment() et appeler setArguments() manuellement dessus. Lorsque Android a besoin de recréer le fragment (changement d'orientation ou faible mémoire), il appelle le constructeur ImageRotatorFragment(), puis transmet le même argument Bundle avec mes valeurs, qui sont définies correctement.

J'ai donc recherché l'approche "suggérée" et ai vu beaucoup d'exemples utilisant newInstance() pour créer Fragments avec des paramètres, ce qui semble faire la même chose que mon constructeur. J'ai donc fait le mien pour le tester, et cela fonctionne aussi parfaitement qu'avant, moins Lint qui se lamente à ce sujet.

public static ImageRotatorFragment newInstance(int imageResourceId) {
    Log.v(TAG, "newInstance(int imageResourceId)");

    ImageRotatorFragment imageRotatorFragment = new ImageRotatorFragment();

    // Get arguments passed in, if any
    Bundle args = imageRotatorFragment.getArguments();
    if (args == null) {
        args = new Bundle();
    }
    // Add parameters to the argument bundle
    args.putInt(KEY_ARG_IMAGE_RES_ID, imageResourceId);
    imageRotatorFragment.setArguments(args);

    return imageRotatorFragment;
}

Personnellement, je trouve que l’utilisation de constructeurs est une pratique beaucoup plus courante que de savoir utiliser newInstance() et de passer des paramètres. Je crois que vous pouvez utiliser cette même technique de constructeur avec Activités et Lint ne s'en plaindra pas. En gros, ma question est la suivante: pourquoi Google ne veut-il pas que vous utilisiez des constructeurs avec des paramètres pour Fragments?

Ma seule hypothèse est de ne pas essayer de définir une variable d'instance sans utiliser la variable Bundle, qui ne sera pas définie lorsque la variable Fragment sera recréée. En utilisant une méthode static newInstance(), le compilateur ne vous laissera pas accéder à une variable d'instance. 

public ImageRotatorFragment(int imageResourceId) {
    Log.v(TAG, "ImageRotatorFragment(int imageResourceId)");

    mImageResourceId = imageResourceId;
}

Je ne pense toujours pas que cela soit une raison suffisante pour interdire l'utilisation de paramètres dans les constructeurs. Quelqu'un d'autre a un aperçu de cela?

54
Steven Byle

Je trouve personnellement que l'utilisation de constructeurs est une pratique beaucoup plus courante que de savoir utiliser newInstance () et de passer des paramètres.

Le modèle de méthode factory est utilisé assez fréquemment dans le développement de logiciels modernes.

En gros, ma question est la suivante: pourquoi Google ne veut-il pas que vous utilisiez des constructeurs avec des paramètres pour les fragments?

Vous avez répondu à votre propre question:

Ma seule hypothèse est de ne pas essayer de définir une variable d'instance sans utiliser Bundle, qui ne le sera pas lorsque le fragment sera recréé.

Correct.

Je ne pense toujours pas que cela soit une raison suffisante pour interdire l'utilisation de paramètres dans les constructeurs.

Vous êtes les bienvenus à votre avis. Vous pouvez désactiver cette vérification, soit par constructeur, soit par espace de travail.

59
CommonsWare

Android ne recrée que les fragments qu'il tue à l'aide du constructeur par défaut. Ainsi, toute initialisation que nous effectuons dans des constructeurs supplémentaires sera perdue. Par conséquent, les données seront perdues.

0
Jatin Sachdeva