web-dev-qa-db-fra.com

Recevoir le résultat de DialogFragment

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.

212
James Cross

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é.

236
Timmmm

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();

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.

129
Assaf Gamliel

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.

45
Brandon

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");

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();
    }
18
vikas kumar

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.

7
ZeWolfe15

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

7
lcompare

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 .

6
Adil Hussain

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

1
Malachiasz

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);
1
Lanitka

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");
}
0
Yessy

À 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

0
Irvin Joao