J'ai un fragment qui ouvre une Dialogfragment
pour obtenir une entrée utilisateur (une chaîne et un entier). Comment puis-je renvoyer ces deux choses dans le fragment?
Voici mon DialogFragment:
public class DatePickerFragment extends DialogFragment {
String Month;
int Year;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().setTitle(getString(R.string.Date_Picker));
View v = inflater.inflate(R.layout.date_picker_dialog, container, false);
Spinner months = (Spinner) v.findViewById(R.id.months_spinner);
ArrayAdapter<CharSequence> monthadapter = ArrayAdapter.createFromResource(getActivity(),
R.array.Months, R.layout.picker_row);
months.setAdapter(monthadapter);
months.setOnItemSelectedListener(new OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int monthplace, long id) {
Month = Integer.toString(monthplace);
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
Spinner years = (Spinner) v.findViewById(R.id.years_spinner);
ArrayAdapter<CharSequence> yearadapter = ArrayAdapter.createFromResource(getActivity(),
R.array.Years, R.layout.picker_row);
years.setAdapter(yearadapter);
years.setOnItemSelectedListener(new OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int yearplace, long id) {
if (yearplace == 0){
Year = 2012;
}if (yearplace == 1){
Year = 2013;
}if (yearplace == 2){
Year = 2014;
}
}
public void onNothingSelected(AdapterView<?> parent) {}
});
Button button = (Button) v.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
getDialog().dismiss();
}
});
return v;
}
}
Je dois envoyer les données après avoir cliqué sur le bouton et avant getDialog().dismiss()
Voici le fragment auquel les données doivent être envoyées:
public class CalendarFragment extends Fragment {
int Year;
String Month;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int position = getArguments().getInt("position");
String[] categories = getResources().getStringArray(R.array.categories);
getActivity().getActionBar().setTitle(categories[position]);
View v = inflater.inflate(R.layout.calendar_fragment_layout, container, false);
final Calendar c = Calendar.getInstance();
SimpleDateFormat month_date = new SimpleDateFormat("MMMMMMMMM");
Month = month_date.format(c.getTime());
Year = c.get(Calendar.YEAR);
Button button = (Button) v.findViewById(R.id.button);
button.setText(Month + " "+ Year);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new DatePickerFragment().show(getFragmentManager(), "MyProgressDialog");
}
});
return v;
}
}
ainsi, une fois que l'utilisateur sélectionne une date dans la Dialogfragment
, il doit renvoyer le mois et l'année.
Ensuite, le texte sur le bouton doit changer pour le mois et l'année spécifiés par l'utilisateur.
NOTE: Outre un ou deux appels spécifiques au fragment Android, il s'agit d'une recette générique pour la mise en œuvre de l'échange de données entre composants faiblement couplés. Vous pouvez utiliser cette approche en toute sécurité pour échanger des données entre tout, que ce soit des fragments, des activités, des dialogues ou tout autre élément de votre application.
Voici la recette:
interface
(nommée MyContract
) contenant une signature de la méthode permettant de transmettre les données, c.-à-d. methodToPassData(... data);
.DialogFragment
remplit ce contrat (ce qui signifie généralement implémente l'interface souhaitée): class MyFragment extends Fragment implements MyContract {....}
DialogFragment
, définissez votre appelant Fragment
comme son fragment cible } _ en appelant myDialogFragment.setTargetFragment(this, 0);
. C'est l'objet avec lequel vous allez parler plus tard.DialogFragment
, récupérez ce fragment appelant en appelant getTargetFragment();
et convertissez objet renvoyé vers l'interface de contrat créée à l'étape 1, à l'aide de: MyContract mHost = (MyContract)getTargetFragment();
. Casting nous permet de nous assurer que l'objet cible implémente le contrat requis et que nous pouvons nous attendre à ce que methodToPassData()
soit présent. Si ce n'est pas le cas, vous aurez alors ClassCastException
régulier. Cela ne devrait normalement pas arriver, à moins que vous ne fassiez trop de codage copier-coller :) Si votre projet utilise du code externe, des bibliothèques ou des plugins, etc., dans ce cas, attrapez plutôt l'exception et indiquez à l'utilisateur que le plugin n'est pas compatible au lieu de laissez simplement l'application se bloquer.methodToPassData()
sur l'objet que vous avez obtenu précédemment: ((MyContract)getTargetFragment()).methodToPassData(data);
. Si votre onAttach()
transforme et assigne déjà le fragment cible à une variable de classe (c.-à-d. mHost
), alors ce code serait simplement mHost.methodToPassData(data);
.Vous venez de transmettre avec succès vos données de la boîte de dialogue à l'appel de fragment.
Voici une autre recette sans utiliser aucune interface. En utilisant simplement les variables setTargetFragment
et Bundle
pour transmettre des données entre DialogFragment et Fragment.
public static final int DATEPICKER_FRAGMENT = 1; // class variable
1 . Appelez la DialogFragment
comme indiqué ci-dessous:
// create dialog fragment
DatePickerFragment dialog = new DatePickerFragment();
// optionally pass arguments to the dialog fragment
Bundle args = new Bundle();
args.putString("pickerStyle", "fancy");
dialog.setArguments(args);
// setup link back to use and display
dialog.setTargetFragment(this, DATEPICKER_FRAGMENT);
dialog.show(getFragmentManager().beginTransaction(), "MyProgressDialog")
2 . Utilisez la variable supplémentaire Bundle
dans une Intent
dans la DialogFragment
pour transmettre toute information au fragment cible. Le code ci-dessous dans l'événement Button#onClick()
de DatePickerFragment
transmet une chaîne et un entier.
Intent i = new Intent()
.putExtra("month", getMonthString())
.putExtra("year", getYearInt());
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, i);
dismiss();
3 . Utilisez la méthode CalendarFragment
's onActivityResult()
pour lire les valeurs:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case DATEPICKER_FRAGMENT:
if (resultCode == Activity.RESULT_OK) {
Bundle bundle = data.getExtras();
String mMonth = bundle.getString("month", Month);
int mYear = bundle.getInt("year");
Log.i("PICKER", "Got year=" + year + " and month=" + month + ", yay!");
} else if (resultCode == Activity.RESULT_CANCELED) {
...
}
break;
}
}
Un bon conseil est d’utiliser l’approche ViewModel et LiveData qui est la meilleure solution. Voici un exemple de code sur la manière de partager des données entre fragments:
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.Java)
} ?: throw Exception("Invalid Activity")
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
class DetailFragment : Fragment() {
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.Java)
} ?: throw Exception("Invalid Activity")
model.selected.observe(this, Observer<Item> { item ->
// Update the UI
})
}
}
Essayez, ces nouveaux composants viennent nous aider, je pense que c'est plus efficace qu'une autre approche.
En savoir plus à ce sujet: https://developer.Android.com/topic/libraries/architecture/viewmodel