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.
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. ).
Ce n'est pas un moyen encapsulé, mais j'ai fini par "tirer" le bundle de l'activité parent:
Bundle bundle = getActivity().getIntent().getExtras();
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.
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:
Parcelable
mais seulement ce qui peut être défini comme Android AttributesLa 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 .