[Из песочницы] Возврат результата выполнения из DialogFragment во Fragment минуя Activity
Введение В этой публикации я покажу, как можно передавать события из DialogFrament в вызывающий Fragment минуя Activity.В официальном Guide по Dialogs есть раздел PassingEvents. В нем рассказано, как вернуть результат работы DialogFragment в вызывающую Activity. Для этого создается дополнительный интерфейс. Activity реализует этот интерфейс, а у DialogFrament есть ссылка на Activity.
Если инициатором вызова DialogFragment является другой Fragment, то в таком подходе нам придется сначала отправить результат в Activity, а потом уже из Activity в заинтересованный в данных Fragment. Отсюда и минусы:
Activity знает о деталях реализации фрагмента (сегодня это дополнительный диалог, а завтра можем реализовать все на одном фрагменте); дополнительный код (больше кода = больше возможностей для ошибок). К счастью, у класса Fragment есть 3 метода, которые позволят реализовать передачу событий из одного фрагмента в другой фрагмент минуя Activity. Это: Суть метода Вызывающий фрагмент: с помощью setTargetFragment устанавливает себя в качестве targetFrament и устанавливает requestCode; реализует метод onActivityResult в котором обрабатывает requestCode и resultCode, а также имеет доступ к дополнительным данным через intent. Вызываемый фрагмент: c помощью getTargetFrament получает ссылку на вызывающий фрагмент; с помощью getTargetRequestCode получает код с которым он был вызыван; вызывает onActivityResult вызывающего фрагмента и передает результаты своего выполнения через resultCode и Intent (для дополнительных). Ниже пример кода. Для простоты оставил только актуальные для статьи части.Вызывающий фрагмент:
public class HostFragment extends Fragment { private static final int REQUEST_WEIGHT = 1; private static final int REQUEST_ANOTHER_ONE = 2; public void openWeightPicker () { DialogFragment fragment = new WeightDialogFragment (); fragment.setTargetFragment (this, REQUEST_WEIGHT); fragment.show (getFragmentManager (), fragment.getClass ().getName ()); }
@Override public void onActivityResult (int requestCode, int resultCode, Intent data) { super.onActivityResult (requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) { switch (requestCode) { case REQUEST_WEIGHT: int weight = data.getIntExtra (WeightDialogFragment.TAG_WEIGHT_SELECTED, -1) //используем полученные результаты //… break; case REQUEST_ANOTHER_ONE: //… break; //обработка других requestCode } updateUI (); } } } Вызываемый фрагмент: public class WeightDialogFragment extends DialogFragment { //тэг для передачи результата обратно public static final String TAG_WEIGHT_SELECTED = «weight»; @NonNull @Override public Dialog onCreateDialog (Bundle savedInstanceState) { LayoutInflater inflater = getActivity ().getLayoutInflater (); View view = inflater.inflate (…, null); AlertDialog.Builder builder = new AlertDialog.Builder (getActivity ()); builder.setView (view) .setPositiveButton («Ok», new DialogInterface.OnClickListener () { @Override public void onClick (DialogInterface dialog, int which) { //отправляем результат обратно Intent intent = new Intent (); intent.putExtra (TAG_WEIGHT_SELECTED, mNpWeight.getValue ()); getTargetFragment ().onActivityResult (getTargetRequestCode (), Activity.RESULT_OK, intent); } }); return builder.create (); }
} Заключение Перечисленные в начале статьи минусы в таком подходе отсутствуют. Только два взаимодействующих элемента знают друг о друге. Для остальных это уже неизвестные детали реализации.Мне бы хотелось узнать, о таком варианте реализации еще при изучении официального гида по диалогам. Я же узнал позже благодаря StackOverflow.