Как сделать так, чтобы действие уведомляло фрагмент о том, что кнопка «Назад» была нажата

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

У меня есть действие со стеком из 3 фрагментов поверх него, все из которых представлены с использованием транзакций FragmentManager и добавлены в задний стек. Пока третий фрагмент активен, мне нужно перехватить метод onBackPressed() и выполнить некоторые дополнительные действия, прежде чем фрагмент будет уничтожен.

Я пытался использовать обратные вызовы и интерфейсы, чтобы захватить onBackPressed() в действии и безуспешно отправить его в 3-й фрагмент.

Каков правильный способ, чтобы фрагмент глубоко в стеке наблюдал за методом Activity onBackPressed().

Дайте мне знать, если это не ясно.

Спасибо за помощь.


person Sev    schedule 03.07.2015    source источник
comment
Нужен ли onBackPressed()? Или вы просто пытаетесь что-то сделать, пока фрагмент уничтожается?   -  person Evan Bashir    schedule 04.07.2015
comment
Может быть, будет лучше переопределить onPause?   -  person Damian Kozlak    schedule 04.07.2015
comment
Последние 2 фрагмента в стеке должны быть извлечены одновременно или один сразу после друг друга, и я отлично справляюсь с этой встроенной кнопкой отмены, вызывая popBackStack() 2 раза (вероятно, не лучший способ сделать это...), поэтому мне нужно сделать то же самое onBackPressed(), иначе будет уничтожен только 1 фрагмент.   -  person Sev    schedule 04.07.2015
comment
Вы читали веб-страницу developer.android.com/training/implementing- навигация/ ? Я думаю, что на этом этапе вы должны опубликовать соответствующий код, чтобы мы могли увидеть возможные проблемы.   -  person The Original Android    schedule 04.07.2015


Ответы (3)


Не скомпилировано и не протестировано, но это излагает основной подход:

public interface BackButonListener {
    boolean OnBackButtonPressed();
} 

public interface BackButtonWatchable {
     void addBackButtonListener(BackButtonListener listener);
     void removeBackButtonListener(BackButtonListener listener);
}

public class MyActivity extends Activity implements BackButtonWatchable {
...
    private static ArrayList<BackButtonListener> backButtonListeners
        = new ArrayList<BackButtonListener>();
    @Override 
    public void addBackButtonListener(BackButtonListener listener) {
          backButtonListeners.add(listener);
    }
    @Override
    public void removeBackButtonListener(BackButtonListener listener) {
          backButtonListeners.remove(listener);
    }
...
    @Override 
    public void onBackButtonPressed() 
    {
        boolean supressBackButton = false;
        for (BackButtonListener listener: backButtonListeners)
        {
             if (!listener.OnBackButtonPressed()) {
                  suppressBackButton = true;
             }
        }
        if (!suppressBackButton) {
            super.onBackButtonPressed();
        }
    }
}


public class MyFragment extends Fragment implements BackButtonListerer {
     @Override 
     public void onResume()
     {
          ((BackButtonWatchable)getActivity()).addBackButtonListener(this);
     }
     @Override 
     public void onPause()     {
          ((BackButtonWatchable)getActivity()).removeBackButtonListener(this);
     }
}
person Robin Davies    schedule 03.07.2015
comment
Чтобы было ясно, мы имеем дело с действием и фрагментом, оба интерфейса находятся в действии или один в действии, а другой во фрагменте? - person Sev; 04.07.2015
comment
Я предлагал, чтобы интерфейсы были объявлены на верхнем уровне. Не принадлежат деятельности. Если вы хотите использовать свой фрагмент только в одном действии, вы можете просто передать значение Fragment.getActivity() в свой класс верхнего уровня и вообще не использовать интерфейс. - person Robin Davies; 04.07.2015
comment
... Вероятно, правильный шаблон - объявить интерфейсы во фрагменте. В этом случае BackButtonWatchable следует переименовать в MyFragment.MyFragmentListener. (отличный шаблон для фрагментов), а затем любое действие, содержащее фрагмент, должно реализовывать MyFragment.MyFragmentListener. Заманчиво просто привести MyFragment.getActivity() к вашему классу верхнего уровня, но если вы когда-нибудь захотите повторно разместить фрагмент в другом действии, все усложнится. Интерфейс MyFragmentListener полезен тем, что заставляет вас сохранять связь между фрагментом и действием скудной и средней. - person Robin Davies; 04.07.2015

Крит интерфейс

public interface OnBackPressedListener {
   void onBackPressed();
}

и создайте поле в деятельности

private OnBackPressedListener mListener;

и ваш onBackPressed() должен выглядеть так

if (mListener != null) {
   mListener.onBackPressed();
} else { /* do your acitivty usual stuff */ }

Когда фрагмент создан, вы регистрируете этот фрагмент как mListener в своей деятельности и не забываете установить для него значение null в onDestroy.

person Yaroslav    schedule 03.07.2015

Это сообщение, которое ответило на мой вопрос. Для новичка в Android это подсказало мне, куда все нужно идти.

https://stackoverflow.com/a/30865486/2640458

Фрагмент, который должен был увидеть метод onBackPress() из его активности:

public class RatingFragment extends Fragment implements ContentActivity.OnBackPressedListener  {

@Override
public void doBack() {
    getFragmentManager().popBackStack();
}

Очень важная подписка на слушателя в приведенном выше фрагменте:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_rating, container, false);

    ((ContentActivity)getActivity()).setOnBackPressedListener(this);
}

Активность, которая должна отправить метод onBackPress() в приведенный выше фрагмент:

public class ContentActivity extends Activity {

protected OnBackPressedListener onBackPressedListener;

public interface OnBackPressedListener {
    void doBack();
}

public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
    this.onBackPressedListener = onBackPressedListener;
}

@Override
public void onBackPressed() {
    if (onBackPressedListener != null)
        onBackPressedListener.doBack();
    else
        super.onBackPressed();
}

@Override
protected void onDestroy() {
    onBackPressedListener = null;
    super.onDestroy();
}
}
person Sev    schedule 04.07.2015
comment
Выглядит хорошо, поздравляю! Ваш ответ похож на другие опубликованные ответы. Вы можете выразить свою признательность, проголосовав за другие сообщения просто за то, что они были полезными. - person The Original Android; 04.07.2015