Введение
В этой публикации я покажу, как можно передавать события из DialogFrament в вызывающий Fragment минуя Activity.
В официальном Guide по Dialogs есть раздел PassingEvents. В нем рассказано, как вернуть результат работы DialogFragment в вызывающую Activity. Для этого создается дополнительный интерфейс. Activity реализует этот интерфейс, а у DialogFrament есть ссылка на Activity.
Если инициатором вызова DialogFragment является другой Fragment, то в таком подходе нам придется сначала отправить результат в Activity, а потом уже из Activity в заинтересованный в данных Fragment. Отсюда и минусы:
- Activity знает о деталях реализации фрагмента (сегодня это дополнительный диалог, а завтра можем реализовать все на одном фрагменте);
- дополнительный код (больше кода = больше возможностей для ошибок).
К счастью, у класса Fragment есть 3 метода, которые позволят реализовать передачу событий из одного фрагмента в другой фрагмент минуя Activity. Это:
- void setTargetFragment(Fragment fragment, int requestCode)
- Fragment getTargetFrament
- int getTargetRequestCode()
Суть метода
Вызывающий фрагмент:
- с помощью 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.
ссылка на оригинал статьи http://habrahabr.ru/post/259805/
Добавить комментарий