J'utilise DialogFragments pour un certain nombre de choses: choisir un élément de la liste, saisir du texte.
Quel est le meilleur moyen de renvoyer une valeur (c'est-à-dire une chaîne ou un élément d'une liste) à l'activité/au fragment appelant?
Actuellement, je fais en sorte que l'activité d'appel mette en oeuvre la variable DismissListener
et que le DialogFragment fasse référence à l'activité. La boîte de dialogue appelle ensuite la méthode OnDimiss
dans l'activité, qui récupère le résultat à partir de l'objet DialogFragment. Très en désordre et cela ne fonctionne pas sur le changement de configuration (changement d'orientation) car le DialogFragment perd la référence à l'activité.
Merci pour toute aide.
Utilisez myDialogFragment.setTargetFragment(this, MY_REQUEST_CODE)
à partir de l'endroit où vous affichez la boîte de dialogue, puis lorsque votre boîte de dialogue est terminée, vous pouvez appeler la fonction getTargetFragment().onActivityResult(getTargetRequestCode(), ...)
et implémenter la fonction onActivityResult()
dans le fragment contenant.
Cela ressemble à un abus de onActivityResult()
, d’autant plus que cela n’implique aucune activité. Mais je l'ai vu recommandé par les personnes officielles de Google, et peut-être même dans les démos de l'API. Je pense que c’est pour cela que g/setTargetFragment()
a été ajouté.
Comme vous pouvez le constater ici il existe un moyen très simple de le faire.
Dans votre DialogFragment
, ajoutez un écouteur d'interface tel que:
public interface EditNameDialogListener {
void onFinishEditDialog(String inputText);
}
Ajoutez ensuite une référence à cet auditeur:
private EditNameDialogListener listener;
Ceci sera utilisé pour "activer" la ou les méthodes d'écoute, ainsi que pour vérifier si l'activité/le fragment parent implémente cette interface (voir ci-dessous).
Dans la variable Activity
/FragmentActivity
/Fragment
"appelée" DialogFragment
, implémentez simplement cette interface.
Dans votre DialogFragment
, tout ce que vous devez ajouter au moment où vous souhaitez ignorer le DialogFragment
et renvoyer le résultat est le suivant:
listener.onFinishEditDialog(mEditText.getText().toString());
this.dismiss();
Où mEditText.getText().toString()
est ce qui sera transmis à l'appelant Activity
.
Notez que si vous voulez retourner quelque chose d'autre, changez simplement les arguments pris par l'écouteur.
Enfin, vous devez vérifier si l’interface a bien été implémentée par l’activité/le fragment parent:
@Override
public void onAttach(Context context) {
super.onAttach(context);
// Verify that the Host activity implements the callback interface
try {
// Instantiate the EditNameDialogListener so we can send events to the Host
listener = (EditNameDialogListener) context;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(context.toString()
+ " must implement EditNameDialogListener");
}
}
Cette technique est très flexible et permet de rappeler le résultat même si vous ne voulez pas fermer la boîte de dialogue pour le moment.
Il existe un moyen beaucoup plus simple de recevoir un résultat d'un DialogFragment.
Tout d'abord, dans votre activité, fragment ou fragment d'activité, vous devez ajouter les informations suivantes:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Stuff to do, dependent on requestCode and resultCode
if(requestCode == 1) { // 1 is an arbitrary number, can be any int
// This is the return result of your DialogFragment
if(resultCode == 1) { // 1 is an arbitrary number, can be any int
// Now do what you need to do after the dialog dismisses.
}
}
}
La requestCode
est fondamentalement votre étiquette int pour le DialogFragment que vous avez appelé, je vais montrer comment cela fonctionne dans une seconde. Le resultCode est le code que vous renvoyez à partir du DialogFragment, indiquant à votre activité, votre fragment ou votre fragment d'activité restant en attente ce qui s'est passé.
Le code suivant est l’appel à DialogFragment. Un exemple est ici:
DialogFragment dialogFrag = new MyDialogFragment();
// This is the requestCode that you are sending.
dialogFrag.setTargetFragment(this, 1);
// This is the tag, "dialog" being sent.
dialogFrag.show(getFragmentManager(), "dialog");
Avec ces trois lignes, vous déclarez votre DialogFragment et définissez un requestCode (qui appellera onActivityResult (...) une fois que la boîte de dialogue est fermée et que vous affichez la boîte de dialogue. C'est aussi simple que cela.
Maintenant, dans votre DialogFragment, vous devez simplement ajouter une ligne directement avant la dismiss()
afin que vous renvoyiez un resultCode à onActivityResult ().
getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, getActivity().getIntent());
dismiss();
C'est tout. Notez que le resultCode est défini en tant que int resultCode
que j'ai défini à resultCode = 1;
dans ce cas.
Voilà, vous pouvez maintenant renvoyer le résultat de votre DialogFragment à votre activité d'appel, à votre fragment ou à votre fragment d'activité.
De plus, il semblerait que cette information ait déjà été publiée, mais comme il n'y avait pas suffisamment d'exemple, je pensais donner plus de détails.
EDIT 06.24.2016 Je m'excuse pour le code trompeur ci-dessus. Mais vous ne pouvez certainement pas recevoir le résultat de nouveau en tant que ligne:
dialogFrag.setTargetFragment(this, 1);
définit une cible Fragment
et non Activity
. Donc, pour ce faire, vous devez utiliser la méthode InterfaceCommunicator
.
Dans votre DialogFragment
, définissez une variable globale
public InterfaceCommunicator interfaceCommunicator;
Créer une fonction publique pour le gérer
public interface InterfaceCommunicator {
void sendRequestCode(int code);
}
Puis, lorsque vous êtes prêt à renvoyer le code à la Activity
une fois que la DialogFragment
est terminée, vous ajoutez simplement la ligne avant de dismiss();
votre DialogFragment
:
interfaceCommunicator.sendRequestCode(1); // the parameter is any int code you choose.
Dans votre activité, vous devez maintenant faire deux choses, la première consiste à supprimer cette ligne de code qui n'est plus applicable:
dialogFrag.setTargetFragment(this, 1);
Ensuite, implémentez l'interface et vous avez terminé. Vous pouvez le faire en ajoutant la ligne suivante à la clause implements
tout en haut de votre classe:
public class MyClass Activity implements MyDialogFragment.InterfaceCommunicator
Et puis @Override
la fonction dans l'activité,
@Override
public void sendRequestCode(int code) {
// your code here
}
Vous utilisez cette méthode d'interface comme vous le feriez avec la méthode onActivityResult()
. Sauf que la méthode d'interface est pour DialogFragments
et l'autre pour Fragments
.
Eh bien, il est peut-être trop tard pour répondre, mais voici ce que j’ai fait pour obtenir les résultats de DialogFragment
. très similaire à la réponse de @ brandon . Ici, j'appelle DialogFragment
à partir d'un fragment, placez simplement ce code à l'endroit où vous appelez votre boîte de dialogue.
FragmentManager fragmentManager = getFragmentManager();
categoryDialog.setTargetFragment(this,1);
categoryDialog.show(fragmentManager, "dialog");
où categoryDialog
est ma DialogFragment
que je souhaite appeler et après cela, dans votre implémentation de dialogfragment
, placez ce code dans lequel vous définissez vos données dans l'intention. La valeur de resultCode
est 1, vous pouvez le définir ou utiliser le système défini.
Intent intent = new Intent();
intent.putExtra("listdata", stringData);
getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, intent);
getDialog().dismiss();
il est maintenant temps de revenir au fragment appelant et d’implémenter cette méthode. vérifiez la validité des données ou la réussite des résultats si vous voulez avec resultCode
et requestCode
in if condition.
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//do what ever you want here, and get the result from intent like below
String myData = data.getStringExtra("listdata");
Toast.makeText(getActivity(),data.getStringExtra("listdata"),Toast.LENGTH_SHORT).show();
}
Un moyen simple que j’ai trouvé est le suivant: Implémentez c’est votre dialogFragment,
CallingActivity callingActivity = (CallingActivity) getActivity();
callingActivity.onUserSelectValue("insert selected value here");
dismiss();
Et ensuite, dans l'activité appelée Fragment de dialogue, créez la fonction appropriée en tant que telle:
public void onUserSelectValue(String selectedValue) {
// TODO add your implementation.
Toast.makeText(getBaseContext(), ""+ selectedValue, Toast.LENGTH_LONG).show();
}
Le Toast doit montrer que cela fonctionne. Travaillé pour moi.
Approche différente, pour permettre à un fragment de communiquer jusqu’à son activité:
1) Définit une interface publique dans le fragment et crée une variable pour celle-ci
public OnFragmentInteractionListener mCallback;
public interface OnFragmentInteractionListener {
void onFragmentInteraction(int id);
}
2) Transforme l'activité en variable mCallback dans le fragment
try {
mCallback = (OnFragmentInteractionListener) getActivity();
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
3) Implémentez l'écouteur dans votre activité
public class MainActivity extends AppCompatActivity implements DFragment.OnFragmentInteractionListener {
//your code here
}
4) Remplacer OnFragmentInteraction dans l'activité
@Override
public void onFragmentInteraction(int id) {
Log.d(TAG, "received from fragment: " + id);
}
Plus d'informations à ce sujet: https://developer.Android.com/training/basics/fragments/communicating.html
Je suis très surpris de voir que personne n'a suggéré d'utiliser des émissions locales pour la communication de DialogFragment
à Activity
! Je trouve que c'est tellement plus simple et plus propre que d'autres suggestions. Essentiellement, vous vous inscrivez sur votre Activity
pour écouter les émissions et vous envoyez les émissions locales à partir de vos instances DialogFragment
. Simple. Pour un guide pas à pas sur la manière de tout configurer, voir ici .
Ou partagez ViewModel comme montré ici:
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// Update the UI.
});
}
}
https://developer.Android.com/topic/libraries/architecture/viewmodel#sharing_data_between_fragments
Dans mon cas, je devais passer des arguments à un targetFragment. Mais j'ai eu l'exception "Fragment déjà actif". J'ai donc déclaré une interface dans mon DialogFragment que parentFragment a implémenté. Lorsque parentFragment a démarré un DialogFragment, il s’est défini en tant que TargetFragment. Puis dans DialogFragment j'ai appelé
((Interface)getTargetFragment()).onSomething(selectedListPosition);
si vous voulez envoyer des arguments et recevoir le résultat du deuxième fragment, vous pouvez utiliser Fragment.setArguments pour accomplir cette tâche.
static class FirstFragment extends Fragment {
final Handler mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 101: // receive the result from SecondFragment
Object result = msg.obj;
// do something according to the result
break;
}
};
};
void onStartSecondFragments() {
Message msg = Message.obtain(mUIHandler, 101, 102, 103, new Object()); // replace Object with a Parcelable if you want to across Save/Restore
// instance
putParcelable(new SecondFragment(), msg).show(getFragmentManager().beginTransaction(), null);
}
}
static class SecondFragment extends DialogFragment {
Message mMsg; // arguments from the caller/FirstFragment
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);
mMsg = getParcelable(this);
}
void onClickOK() {
mMsg.obj = new Object(); // send the result to the caller/FirstFragment
mMsg.sendToTarget();
}
}
static <T extends Fragment> T putParcelable(T f, Parcelable arg) {
if (f.getArguments() == null) {
f.setArguments(new Bundle());
}
f.getArguments().putParcelable("extra_args", arg);
return f;
}
static <T extends Parcelable> T getParcelable(Fragment f) {
return f.getArguments().getParcelable("extra_args");
}
À Kotlin
// My DialogFragment
class FiltroDialogFragment: DialogFragment (), View.OnClickListener {
var listener: InterfaceCommunicator? = null
override fun onAttach(context: Context?) {
super.onAttach(context)
listener = context as InterfaceCommunicator
}
interface InterfaceCommunicator {
fun sendRequest(value: String)
}
override fun onClick(v: View) {
when (v.id) {
R.id.buttonOk -> {
//You can change value
listener?.sendRequest('send data')
dismiss()
}
}
}
}
// Mon activité
classe MyActivity: AppCompatActivity (), FiltroDialogFragment.InterfaceCommunicator {
override fun sendRequest(value: String) {
// :)
Toast.makeText(this, value, Toast.LENGTH_LONG).show()
}
}
J'espère que ça sert, si vous pouvez améliorer s'il vous plaît éditez-le . Mon anglais n'est pas très bon