Управление деятельностью из DialogFragment

Как я могу вызвать finish() и другие нестатические методы из диалогового окна DialogFragment в его деятельности? Я пробовал передавать сообщения из OnClickLisener в DialogFragment, но безрезультатно.

У меня действительно простое приложение, поддерживающее MainActivity и DialogFragment:

    public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle arg0) {
    super.onCreate(arg0);
    setContentView(R.layout.activity);
    showDialog();
}
public void showDialog() {
    DialogFragment newFragment = new ConfirmDialog();
    newFragment.show(getFragmentManager(), "dialog");
}

} И Диалог снова очень прост:

public class ConfirmDialog extends DialogFragment {
@Override
public AlertDialog onCreateDialog(Bundle savedInstanceState) {
    // Use the Builder class for convenient dialog construction
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setMessage("Confirm you want to continue?")
           .setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                   //finish() MainActvity
                  }
               })
           .setNegativeButton("No.", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                 //Do nothing in MainActity
               }
           });
    // Create the AlertDialog object and return it
    return builder.create();
}

}

Ответ 1

Есть много вариантов. Один из них определяет интерфейс с одним методом внутри.

  • Попросите вызывающего диалогового окна реализовать этот интерфейс.
  • Храните глобальную переменную, указывающую на вызывающего.
  • Задайте переменную в методе onAttach(Activity activity).
  • Отбросить эту переменную в методе onDetach().
  • Вызовите метод переменной (интерфейс) в onClick.

Пример:

public class MainActivity extends Activity implements MyInterface { 
    // ...

    @Override
    public void onChoose() { finish(); }

}

И внутри ConfirmDialog:

public static interface MyInterface {
    public void onChoose();
}

private MyInterface mListener;

@Override
public void onAttach(Activity activity) {
    mListener = (MyInterface) activity;
    super.onAttach(activity);
}

@Override
public void onDetach() {
    mListener = null;
    super.onDetach();
}

И затем вызовите mListener.onChoose() в любом месте вашего класса.


Я знаю, что это было отмечено как принятое, но я решил, что могу предоставить больше отзывов для обсуждения.

Заметка об использовании или отсутствии интерфейсов. Энди отвечает так же правильно, как и мой, поэтому я сказал: "Есть много вариантов. Один из них...".

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

Если вы не уверены, что собираетесь использовать его только один раз, для одной цели (завершения) вам обычно следует избегать упрощения (и упрощения) деталей реализации Activity в вашем классе диалога. Гибкость, абстракция и эффективность. Меньше кода для поддержки.

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

Да, вы могли бы использовать более одного Activity, но вы были бы ограничены finish() ing. Интерфейс даст вам возможность делать все, что угодно, в каждом Activity. Другими словами, до разработчика, чтобы определить, как он должен себя вести для этого события. Вы сами можете содержать подробности реализации.

Как побочный элемент, я создаю пакет со всеми диалоговыми окнами, которые могут понадобиться для моего приложения. Для таких диалоговых окон подтверждения я повторно использую разные сообщения и кнопки. Я предоставляю значения по умолчанию, но также допускаю изменения с помощью setArguments. И я поддерживаю интерфейсы, поэтому мне не нужно создавать один интерфейс для каждого диалога. Разработчик отвечает, в соответствии с которым диалог вызывает "обратный вызов" диалоговых окон. Гибкость, абстракция и эффективность, при этом избегая при этом вещей, любезно называемых Hydra и Royal Family. Так. В конце концов, как я уже сказал, много вариантов. Не переучивайте, но не слишком упрощайте слишком рано (оставляйте место для изящного расширения).

Более важно понимать преимущества и ловушки, чем выбирать этот или другой ответ.

Ответ 2

Несмотря на то, что объем работы, связанной с созданием интерфейса, невелик, я не понимаю, почему вам нужно вызвать finish() из созданной им Activity. Вызов finish() из самого DialogFragment будет достаточным. Если вам по какой-то причине необходимо отправить информацию обратно с ней, вы всегда можете вызвать getActivity() и связать метод, который существует в Activity. В конечном счете, независимо от того, где вы называете финиш, он отделяет Фрагмент и уничтожает его.

Просто, чтобы уточнить, как вызвать метод из вашей Activity в вашем фрагменте

((YourActivity)getActivity()).someMethod(param);

Вы ДОЛЖНЫ использовать его, потому что Java не знает, что у Activity есть любой метод, который вы хотите вызвать. Каким бы вы ни выбрали, удачи:)

веселит

ИЗМЕНИТЬ

Я ценю ваше разъяснение Дэвида. В общем, вы правы. Но, честно говоря, в этом случае вы неверны из-за природы фрагментов и их отношений с Деятельностью. Опять же, вы по существу будете создавать слушателя, чтобы быть вызванным фрагментом, который уже имеет очень тесную связь с классом Activity, которым он удерживается. В этом случае теряются любые преимущества, предоставляемые без использования проводки через слушателей. Вы по-прежнему будете переписывать собственный код для каждого диалога. Хотя в моем методе вы можете написать метод в классе Activity таким образом, что вам только когда-нибудь придется писать его один раз.

Есть только две причины, по которым я вижу необходимость использования Listener:

1. Если вы пишете код, который будут использовать другие люди. Таким образом, вы предоставляете простой способ предоставить информацию при сохранении определенной структуры (например, Androids DatePickerDialog).

2. Если соединение между двумя частями, которые вы пытаетесь поддерживать подключенными (например, GUI на Java), отсутствует.

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

Ответ 3

Возможно, это не лучший способ сделать это, но он работает. В разделе "Создать ссылку на свою активность" создайте статический метод, который вызывает startActivity и завершает работу, и вызовите этот статический метод из вашего диалога, если он "хорошо". Код ниже:

private static Activity mActivity = null;
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mActivity = this;
}

public static void staticMethodToCall(){
         Intent intent = new Intent(mActivity,Second.class);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         mActivity.startActivity(intent);
         mActivity.finish();
    }

И в диалоговом окне

 builder.setMessage("Confirm you want to continue?")
           .setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {

                   TheClassWithTheStaticMetod.staticMethodToCall();
                  }
               })

Ответ 4

Вместо

.setPositiveButton("Yes.", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { //finish() MainActvity } })

Использование

.setPositiveButton( "Да.", новый DialogInterface.OnClickListener() { public void onClick (диалог DialogInterface, int id) {//это получает текущая деятельность.

Активность currentActivity = getActivity();

//этот метод finish() завершает текущую активность.

              currentActivity.finish(); } })