Фрагмент обновления при выборе опции фрагмента диалога

У меня есть фрагмент, который на компоненте вызывает всплывающие окна DialogFragment. Этот фрагмент диалога содержит список опций. Когда выбран вариант из списка, я хочу уведомить фрагмент, чтобы я мог запустить процедуру обновления полей. Я сделал что-то вроде этого

@Override
public void onClick(DialogInterface dialog, int item) {
     updateSharedPreference(item);
     Log.e("ProfilePersonaListDialog", "Click on dialog, inside onClick");
     OnCloseListDialogListener act = (OnCloseListDialogListener) getActivity();
     act.onDialogListSelection();

     dismiss();
}

Однако этот getActivity() вызывает FragmentActivity, а не фрагмент, вызвавший фрагмент диалога. Я мог бы убить текущий открытый/работающий фрагмент и вызвать новый экземпляр, который получит обновленные поля, но это грязное решение, которого я бы предпочел избежать.

Любые предложения, как выполнить это обновление фрагмента после выбора параметра во фрагменте диалога?


person peter_budo    schedule 08.05.2012    source источник
comment
Используя FragmentManager, вы можете добиться того же   -  person Relsell    schedule 06.07.2012


Ответы (3)


Просто возвращаюсь с решением. Моя проблема заключалась в пересылке строки текущего фрагмента getTag() в качестве параметра show() для DialogFragment. Если кому интересно вот рабочий образец.

Создать простой слушатель

public interface OnCloseListDialogListener {
    public void onDialogListSelection();
}

Создайте новый диалог, который будет расширять DialogFragment



public class ListDialogFragment extends DialogFragment implements DialogInterface.OnClickListener {

    private PersonaData[] mPersonaData;
    private String[] mPersonaName;
    private final String TAG;

    public static ListDialogFragment newInstance(PersonaData[] personaData, String tag) {
        ListDialogFragment dialog = new ListDialogFragment(personaData, tag);
        Bundle bundle = new Bundle();
        dialog.setArguments(bundle);
        return dialog;
    }

    private ListDialogFragment(PersonaData[] personaData, String tag) {
        this.mPersonaData = personaData.clone();
        this.TAG = tag;
    }

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setCancelable(true);
        int style = DialogFragment.STYLE_NORMAL, theme = 0;
        setStyle(style, theme);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle(R.string.dialog_title);
        mPersonaName = getData();//Your own implementation here
        builder.setNegativeButton("Cancel", this);
        builder.setSingleChoiceItems(mPersonaName, -1, new SingleChoiceListener());
        return builder.create();

    }

    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    }

    private class SingleChoiceListener implements DialogInterface.OnClickListener {
        @Override
        public void onClick(DialogInterface dialog, int item) {
            updateSharedPreference(item);
            OnCloseListDialogListener act = (OnCloseListDialogListener) getFragmentManager().findFragmentByTag(TAG);
            act.onDialogListSelection();
            dismiss();
        }
    }
}

А затем в фрагменте, из которого вы хотите вызвать этот диалог, сделайте следующее. DIALOG - это просто константа String, которую я поместил туда только диалог


SOME_CLICKABLE.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        FragmentManager manager = getFragmentManager();
        ListDialogFragment dialog = ListDialogFragment.newInstance(mPersona, getTag());
        dialog.show(manager, DIALOG);
    }
});
person peter_budo    schedule 18.06.2012
comment
getTag () по умолчанию возвращает значение null, вам нужно сначала установить его? Также выдерживает ли это вращение, когда фрагмент диалога находится на экране? - person Maxrunner; 16.01.2014

В большинстве случаев необходимо, чтобы Fragment знал, что он работает в контексте Activity с некоторым описанием и допустимым для дочернего фрагмента вызовом метода интерфейса, неявно реализованного родительской активностью (как показано приведением в ваш фрагмент кода). Когда вы заставите свои рекомендации работать, как указывает Томаш, вы станете золотым.

Тем не менее, :) чтобы облегчить повторное использование фрагмента диалога, я бы посоветовал вам использовать BroadcastReceivers. BroadcastReceiver просто передает сообщение о том, что я сделал 'x'. Затем родительская активность или любой другой компонент верхнего уровня может объявить Я прослушиваю 'x'. Как только событие будет запущено в диалоговом компоненте, это событие будет собрано родительской активностью onReceive, где вы можете запустить необходимый код для обновления ваших полей.

На личном уровне я предпочитаю эту слабую связь подходу к интерфейсу приведения, поскольку он заставляет меня думать о назначении каждого фрагмента и сохранять его модульность.

Если вы хотите попробовать, прочитайте раздел руководства разработчика на BroadcastReceivers и выполните следующие шаги;

  1. Внедрите BroadcastReceiver в свою родительскую активность. Обратите внимание, что для реализации требуется метод onReceive.

  2. Переопределите метод onResume родительского действия и зарегистрируйте действие в качестве получателя события с действием намерения "blah". Что-то типа;

     @Override
     protected void onResume() {
     super.onResume();
     registerReceiver(this, new IntentFilter("blah"));
    }
    
  3. Переопределите метод родительской активности onPause и отмените регистрацию активности в качестве получателя, чтобы избежать «утечки получателей» (вы узнаете).

    @Override
    protected void onPause() {
     super.onPause();
     unregisterReceiver(deleteSpotReceiver);
    }
    
  4. В вашем DialogFragment onClick запустите событие, которое ваша родительская активность "прослушивает".

    @Override
    public void onClick(DialogInterface dialog, int item) {
        updateSharedPreference(item);
        Log.e("ProfilePersonaListDialog", "Click on dialog, inside onClick");
        final Intent intent = new Intent();
        intent.setAction("blah");
        getActivity().sendBroadcast(intent);
        dismiss();
    }
    

Родительская активность соберет сообщение, и вы сможете продолжить обработку. Дайте мне знать, если вы решите принять этот метод.

person BrantApps    schedule 15.05.2012
comment
Отличный мини-гид! Было именно то, что я искал. - person Mgamerz; 17.01.2013
comment
Отличный гид! Я все еще не уверен, что обратный вызов отправляется в действие. В моем случае у меня есть ящик навигации, содержащий несколько «основных» фрагментов. Когда действие передает информацию о том, что диалоговое окно было нажато, кажется, что оно немного нарушено. Не лучше ли зарегистрировать слушателя при создании диалога? - person Sam; 28.03.2014
comment
Привет, Сэм, пока базовые фрагменты не понимают, где они находятся в иерархии представлений, подход остается надежным. Если фрагмент A напрямую взаимодействует с фрагментом B/деятельностью B как конкретные типы, то они связаны ненадлежащим образом. Альтернатива обратного вызова популярна, когда фрагмент A не «знает» о том, кто заинтересован, а только о том, что кто-то есть — это может быть выполнено с помощью обратного вызова интерфейса, подобного слушателю, или с помощью подхода EventBus. С точки зрения Android, если вы никогда не пишете ((MySoooperActivityOrFragment) getActivity()).invokeMySooperMethod(), со мной все в порядке;) - person BrantApps; 28.03.2014

Точно так же, как вы сделали это выше, и добавьте что-то подобное в свою деятельность:

public void onDialogListSelection() {
    AnotherFragment anotherFragment = (AnotherFragment) getSupportFragmentManager()
            .findFragmentById(R.id.anotherFragment);
    anotherFragment.customMethodToNotifyListHasBeenSelected();
}

Конечно, если вы не используете библиотеку поддержки, то вызовите getFragmentManager вместо getSupportFragmentManager.

person Tomasz Gawel    schedule 08.05.2012
comment
Не работает, вплоть до того, что этот фрагмент является подфрагментом, вызываемым/используемым нажатием кнопки из другого фрагмента, поэтому я не могу получить идентификатор, также пробовал с тегом, но не удалось :( - person peter_budo; 09.05.2012
comment
@peter_budo: Если вы создаете фрагмент всплывающего окна во время выполнения в своем коде, вы можете сохранить ссылку на него для последующего использования. - person Tomasz Gawel; 09.05.2012
comment
извините, а можно поподробней как? Спасибо - person peter_budo; 09.05.2012
comment
@peter_budo: конечно, если бы вы предоставили свой текущий код, я мог бы сделать несколько предложений. но это просто сохранить созданный фрагмент в поле участника действий. В качестве альтернативы, даже если вы создаете фрагмент во время выполнения, вы все равно можете связать его с тегом. Подсказка: используйте DialogTransaction.add(int containerViewId, Fragment fragment, String tag) вместо DialogTransaction.add(int containerViewId, Fragment fragment)show DailogFragment, похоже, есть только версия с аргументом тега: DailogFragments.show(FragmentTransaction transaction, String tag)) - person Tomasz Gawel; 09.05.2012
comment
Хорошо, вот это ProfileStatsFragment — это место, где я вызываю диалог в строке 126, затем здесь ProfilePersonaListDialog строка 95-99, где должно произойти уведомление о фрагменте. (На данный момент в коде немного беспорядка, я помогаю с проектом) - person peter_budo; 09.05.2012
comment
Я не вижу в ProfileStatsFragment, где вы создаете экземпляр ProfilePersonaListDialog? Это должно выглядеть примерно так: ProfilePersonaListDialog.newInstance(personaData, tag).show(getSupportFragmentManager().beginTransaction(), tag); Здесь вы можете сохранить фрагмент, возвращаемый фабричным методом newInstance, в качестве поля участника активности, но, с другой стороны, у вас есть тег для идентификации этого фрагмента, поэтому, возможно, он не нужен. - person Tomasz Gawel; 09.05.2012
comment
Извините, я плохо связал неправильный фрагмент здесь правильный. Строки 122-126 показывают всю настройку - person peter_budo; 09.05.2012