web-dev-qa-db-fra.com

Si je déclare un fragment dans une présentation XML, comment puis-je lui transmettre un bundle?

J'ai une activité que j'ai remplacée par un fragment. L'activité a pris une intention qui contenait des informations supplémentaires sur les données que l'activité était censée afficher.

Maintenant que mon activité n'est qu'un wrapper autour d'un fragment qui fait le même travail, comment puis-je obtenir ce bundle dans le fragment si je déclare le fragment en XML avec la balise?

Si je devais utiliser une FragmentTransaction pour mettre le Fragment dans un ViewGroup, j'aurais la chance de transmettre ces informations dans le constructeur Fragment, mais je me pose des questions sur la situation où le fragment est défini en XML.

59
Plantage

Maintenant que mon activité n'est qu'un wrapper autour d'un fragment qui fait le même travail, comment puis-je obtenir ce bundle dans le fragment si je déclare le fragment en XML avec la balise?

Tu ne peux pas.

Cependant, vous êtes invités à appeler findFragmentById() sur votre FragmentManager pour récupérer le fragment après gonflage, puis appeler une méthode sur le fragment pour lui associer des données. Bien qu'apparemment cela ne puisse pas être setArguments(), votre fragment pourrait s'arranger pour conserver les données elles-mêmes après un changement de configuration par d'autres moyens (onSaveInstanceState(), setRetainInstance(true), etc. ).

44
CommonsWare

Ce n'est pas un moyen encapsulé, mais j'ai fini par "tirer" le bundle de l'activité parent:

Bundle bundle = getActivity().getIntent().getExtras();
43
Oded Breiner

Une autre option consiste à ne pas déclarer le fragment dans le XML. Je sais que ce n'est pas exactement ce que tu veux faire. Cependant, vous pouvez déclarer une mise en page simple dans votre vue comme ceci:

    <LinearLayout
        Android:id="@+id/fragment_container"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical" />

Et puis, dans votre classe Activity, vous gonflez la mise en page par programme avec le fragment. De cette façon, vous pouvez passer à travers les paramètres à l'aide des arguments.

 FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    MyFragment fragment = MyFragment.newInstance();
    Bundle args = new Bundle();
    args.putInt(Global.INTENT_INT_ROLE, 1);
    fragment.setArguments(args);
    fragmentTransaction.add(R.id.fragment_container, fragment, "MyActivity");
    fragmentTransaction.commit();

Cette approche n'est pas aussi propre et simple que de la déclarer dans le xml, mais je l'ai déplacée car elle vous donne beaucoup plus de contrôle sur le fragment.

9
Zapnologica

Vous ne pouvez pas passer un Bundle mais vous POUVEZ passer des paramètres (ou plutôt des attributs) via XML à un fragment.

Le processus est similaire à comment vous définissez Afficher les attributs personnalisés . Sauf qu'AndroidStudio (actuellement) ne vous aide pas dans le processus.

supposons que c'est votre fragment en utilisant des arguments (j'utiliserai kotlin mais cela fonctionne totalement en Java aussi):

class MyFragment: Fragment() {

    // your fragment parameter, a string
    private var screenName: String? = null

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        if (screenName == null) {
            screenName = arguments?.getString("screen_name")
        }
    }
}

Et vous voulez faire quelque chose comme ça:

<fragment
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:id="@+id/myFragment"
    Android:name="com.example.MyFragment"
    app:screen_name="@string/screen_a"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"/>

Noter la app:screen_name="@string/screen_a"

pour le faire fonctionner, ajoutez simplement ceci dans un fichier de valeurs (fragment_attrs.xml ou choisissez le nom de votre choix):

<!-- define your attribute name and type -->
<attr name="screen_name" format="string|reference"/>

<!-- define a bunch of constants you wanna use -->
<string name="screen_a" translatable="false">ScreenA</string>
<string name="screen_b" translatable="false">ScreeenB</string>

<!-- now define which arguments your fragment is gonna have (can be more then one) -->
<!-- the convention is "FragmentClassName_MembersInjector" -->
<declare-styleable name="MyFragment_MembersInjector">
    <attr name="screen_name"/>
</declare-styleable>

Presque terminé, il vous suffit de le lire dans votre fragment, alors ajoutez la méthode:

override fun onInflate(context: Context?, attrs: AttributeSet?, savedInstanceState: Bundle?) {
    super.onInflate(context, attrs, savedInstanceState)
    if (context != null && attrs != null && screenName == null) {
        val ta = context.obtainStyledAttributes(attrs, R.styleable.MyFragment_MembersInjector)
        if (ta.hasValue(R.styleable.MyFragment_MembersInjector_screen_name)) {
            screenName = ta.getString(R.styleable.MyFragment_MembersInjector_screen_name)
        }
        ta.recycle()
    }
}

et voilá, vos attributs XML dans votre fragment :)

Limites:

  • Android Studio (à partir de maintenant) ne remplit pas automatiquement ces arguments dans le XML de mise en page
  • Vous ne pouvez pas passer Parcelable mais seulement ce qui peut être défini comme Android Attributes
5
Daniele Segato

La seule solution que je vois est de ne pas utiliser les arguments comme canal d'échange de données. Au lieu de cela, faites votre fragment pour obtenir les informations nécessaires ailleurs. Rappelez pour obtenir l'activité appropriée, consultez une mémoire de stockage temporaire, un objet Singleton, etc.

Une autre solution qui peut être utile consiste à utiliser des cadres qui permettent à des objets non liés d'échanger des messages via le modèle de conception Mediator, comme Otto .

3
Renascienza