Ich habe ein Fragment, das eine Dialogfragment
öffnet, um Benutzereingaben zu erhalten (eine Zeichenfolge und eine Ganzzahl). Wie schicke ich diese beiden Dinge zurück zum Fragment?
Hier ist mein 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;
}
}
Ich muss die Daten nach dem Klicken der Schaltfläche und vor getDialog().dismiss()
senden.
Hier ist das Fragment, an das die Daten gesendet werden müssen:
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;
}
}
sobald der Benutzer in der Variablen Dialogfragment
ein Datum auswählt, muss er den Monat und das Jahr zurückgeben.
Dann sollte sich der Text auf der Schaltfläche in dem vom Benutzer angegebenen Monat und Jahr ändern.
HINWEIS: Abgesehen von einem oder zwei spezifischen Android-Fragment-Aufrufen ist dies ein generischer Ansatz für die Implementierung des Datenaustauschs zwischen lose gekoppelten Komponenten. Sie können diesen Ansatz verwenden, um Daten buchstäblich zwischen allem auszutauschen, sei es Fragmente Aktivitäten, Dialoge oder andere Elemente Ihrer Anwendung.
Hier ist das Rezept:
interface
(d. H. Mit MyContract
), das eine Signatur der Methode zum Weiterleiten der Daten enthält, d. H. methodToPassData(... data);
.DialogFragment
-Datei diesen Vertrag erfüllt (was normalerweise bedeutet, dass die gewünschte Schnittstelle implementiert wird): class MyFragment extends Fragment implements MyContract {....}
DialogFragment
setzen Sie Ihr aufrufendes Fragment
als Zielfragment , indem Sie myDialogFragment.setTargetFragment(this, 0);
aufrufen. Dies ist das Objekt, mit dem Sie später sprechen werden.DialogFragment
das aufrufende Fragment auf, indem Sie getTargetFragment();
aufrufen und das zurückgegebene Objekt an die in Schritt 1 erstellte Vertragsschnittstelle senden, indem Sie Folgendes tun: MyContract mHost = (MyContract)getTargetFragment();
. Durch das Casting können wir sicherstellen, dass das Zielobjekt den erforderlichen Vertrag implementiert, und wir können erwarten, dass methodToPassData()
dabei ist. Wenn nicht, erhalten Sie regelmäßig ClassCastException
. Dies sollte normalerweise nicht passieren, es sei denn, Sie machen zuviel Copy-Paste-Coding. :) Wenn Ihr Projekt externen Code, Bibliotheken oder Plugins usw. verwendet, sollten Sie in diesem Fall eher die Ausnahme abfangen und dem Benutzer mitteilen, dass das Plugin nicht kompatibel ist Lassen Sie die App einfach abstürzen.methodToPassData()
für das zuvor erhaltene Objekt auf: ((MyContract)getTargetFragment()).methodToPassData(data);
. Wenn Ihr onAttach()
bereits eine Klassenvariable (d. H. mHost
) umwandelt und einem Zielfragment zuordnet, ist dieser Code nur mHost.methodToPassData(data);
.Sie haben gerade Ihre Daten erfolgreich vom Dialog an den Aufruf des Fragments übergeben.
Hier ist ein anderes Rezept ohne Verwendung einer Schnittstelle. Verwenden Sie einfach die Variablen setTargetFragment
und Bundle
, um Daten zwischen DialogFragment und Fragment zu übergeben.
public static final int DATEPICKER_FRAGMENT = 1; // class variable
1 . Rufen Sie die DialogFragment
wie folgt auf:
// 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 . Verwenden Sie die zusätzliche Bundle
in einer Intent
in der DialogFragment
, um alle Informationen an das Zielfragment zurückzugeben. Der folgende Code im Button#onClick()
-Ereignis von DatePickerFragment
übergibt einen String und eine Ganzzahl.
Intent i = new Intent()
.putExtra("month", getMonthString())
.putExtra("year", getYearInt());
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, i);
dismiss();
3 . Verwenden Sie die onActivityResult()
-Methode von CalendarFragment
, um die Werte zu lesen:
@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;
}
}
Ein guter Tipp ist die Verwendung des ViewModel- und LiveData-Ansatzes, der der beste Weg ist. Bellow ist das Codebeispiel zum Freigeben von Daten zwischen Fragmenten:
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
})
}
}
Probieren Sie es aus, diese neuen Komponenten helfen uns, ich denke, es ist effizienter als andere Ansätze.
Lesen Sie mehr darüber: https://developer.Android.com/topic/libraries/architecture/viewmodel
Hier ist ein Ansatz, der die in Kotlin implementierte Antwort von Marcin veranschaulicht.
1.Erstellen Sie eine Schnittstelle mit einer Methode zum Übergeben von Daten in Ihrer dialogFragment-Klasse.
interface OnCurrencySelected{
fun selectedCurrency(currency: Currency)
}
2.Fügen Sie Ihre Schnittstelle in Ihrem dialogFragment-Konstruktor hinzu.
class CurrencyDialogFragment(val onCurrencySelected :OnCurrencySelected) :DialogFragment() {}
3.Lassen Sie Ihr Fragment nun die gerade erstellte Schnittstelle implementieren
class MyFragment : Fragment(), CurrencyDialogFragment.OnCurrencySelected {
override fun selectedCurrency(currency: Currency) {
//this method is called when you pass data back to the fragment
}}
4.Um dann Ihren Dialog anzuzeigen, rufen Sie einfach CurrencyDialogFragment(this).show(fragmentManager,"dialog")
auf. this
ist das Interface-Objekt, mit dem Sie sprechen, um Daten an Ihr Fragment zurückzugeben.
5.Wenn Sie Daten an Ihr Fragment zurücksenden möchten, rufen Sie einfach die Methode auf, um Daten an das Schnittstellenobjekt zu übergeben, das Sie im dialogFragment-Konstruktor übergeben haben.
onCurrencySelected.selectedCurrency(Currency.USD)
dialog.dismiss()