Как реализовать onBackPressed() в фрагментах?

Есть ли способ реализовать onBackPressed() в Android Fragment аналогично тому, как мы реализуем в Android Activity?

Поскольку жизненный цикл фрагмента не имеет onBackPressed(). Есть ли какой-либо другой альтернативный способ переместить onBackPressed() в фрагменты Android 3.0?

Ответ 1

Я решил таким образом переопределить onBackPressed в Activity. Все FragmentTransaction являются addToBackStack перед коммитом:

@Override
public void onBackPressed() {

    int count = getSupportFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();
        //additional code
    } else {
        getSupportFragmentManager().popBackStack();
    }

}

Ответ 2

Я думаю, что лучшее решение

JAVA SOLUTION

Создать простой интерфейс:

public interface IOnBackPressed {
    /**
     * If you return true the back press will not be taken into account, otherwise the activity will act naturally
     * @return true if your processing has priority if not false
     */
    boolean onBackPressed();
}

И в вашей деятельности

public class MyActivity extends Activity {
    @Override public void onBackPressed() {
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
       if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
          super.onBackPressed();
       }
    } ...
}

Наконец в вашем фрагменте:

public class MyFragment extends Fragment implements IOnBackPressed{
   @Override
   public boolean onBackPressed() {
       if (myCondition) {
            //action not popBackStack
            return true; 
        } else {
            return false;
        }
    }
}

КОТЛИН РЕШЕНИЕ

1 - Создать интерфейс

interface IOnBackPressed {
    fun onBackPressed(): Boolean
}

2 - Подготовьте свою деятельность

class MyActivity : AppCompatActivity() {
    override fun onBackPressed() {
        val fragment =
            this.supportFragmentManager.findFragmentById(R.id.main_container)
        (fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
            super.onBackPressed()
        }
    }
}

3 - Внедрите в свой целевой фрагмент

class MyFragment : Fragment(), IOnBackPressed {
    override fun onBackPressed(): Boolean {
        return if (myCondition) {
            //action not popBackStack
            true
        } else {
            false
        }
    }
}

Ответ 3

В соответствии с ответом @HaMMeRed здесь есть псевдокод, как он должен работать. Допустим, что ваше основное действие называется BaseActivity, у которого есть дочерние фрагменты (например, в примере SlidingMenu lib). Вот шаги:

Сначала нам нужно создать интерфейс и класс, который реализует свой интерфейс, чтобы иметь общий метод

  • Создать интерфейс класса OnBackPressedListener

    public interface OnBackPressedListener {
        public void doBack();
    }
    
  • Создайте класс, который реализует навыки OnBackPressedListener

    public class BaseBackPressedListener implements OnBackPressedListener {
        private final FragmentActivity activity;
    
        public BaseBackPressedListener(FragmentActivity activity) {
            this.activity = activity;
        }
    
        @Override
        public void doBack() {
            activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        }
    }
    
  • С тех пор мы будем работать над нашим кодом BaseActivity и его фрагментами

  • Создайте собственный слушатель поверх своего класса BaseActivity

    protected OnBackPressedListener onBackPressedListener;
    
  • создать метод для установки слушателя в BaseActivity

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }
    
  • в переопределении onBackPressed реализовать что-то вроде этого

    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
    
  • в вашем фрагменте в onCreateView вы должны добавить наш прослушиватель

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        activity = getActivity();
    
        ((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
    
        View view = ... ;
    //stuff with view
    
        return view;
    }
    

Voila, теперь, когда вы щелкаете назад в фрагменте, вы должны поймать свой обычай по обратному методу.

Ответ 4

Это сработало для меня: fooobar.com/questions/25335/...

@Override
public void onResume() {
    super.onResume();

    if(getView() == null){
        return;
    }

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {

            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
                // handle back button click listener
                return true;
            }
            return false;
        }
    });
}

Ответ 5

Если вам нужна такая функциональность, вам нужно переопределить ее в своей деятельности, а затем добавить интерфейс YourBackPressed для всех ваших фрагментов, который вы вызываете для соответствующего фрагмента при каждом нажатии кнопки назад.

Изменение: я хотел бы добавить свой предыдущий ответ.

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

LocalBroadcastManager в библиотеке поддержки может помочь в этом, и вы просто отправляете трансляцию в onBackPressed и подписываетесь на интересующие вас фрагменты. Я думаю, что Messaging является более изолированной реализацией и будет лучше масштабироваться, поэтому сейчас это будет моя официальная рекомендация по внедрению. Просто используйте действие Intent в качестве фильтра для вашего сообщения. отправьте только что созданный ACTION_BACK_PRESSED, отправьте его из своей деятельности и прослушайте в соответствующих фрагментах.

Ответ 6

Ничто из этого легко реализовать и не будет функционировать оптимальным образом.

Фрагменты имеют вызов метода onDetach, который выполнит задание.

@Override
    public void onDetach() {
        super.onDetach();
        PUT YOUR CODE HERE
    }

ЭТО БУДЕТ РАБОТАТЬ.

Ответ 7

Просто добавьте addToBackStack, пока вы переходите между своими фрагментами, как показано ниже:

fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();

если вы пишете addToBackStack(null), он будет обрабатывать его сам по себе, но если вы дадите тег, вы должны обработать его вручную.

Ответ 8

так как этот вопрос и некоторые ответы более пяти лет, позвольте мне поделиться своим решением. Это продолжение и модернизация ответа от @oyenigun

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

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

Сначала определите интерфейс

public interface Backable {
    boolean onBackPressed();
}

Этот интерфейс, который я называю Backable (я сторонник соглашений об именах), имеет единственный метод onBackPressed(), который должен возвращать значение boolean. Нам нужно принудительно ввести логическое значение, потому что нам нужно будет знать, нажала ли кнопка "назад" заднее событие. Возврат true означает, что он имеет, и никаких дальнейших действий не требуется, иначе false говорит, что действие по умолчанию по-прежнему должно иметь место. Этот интерфейс должен быть собственным файлом (желательно в отдельном пакете с именем interfaces). Помните, что разделение ваших классов на пакеты является хорошей практикой.

Во-вторых, найдите верхний фрагмент

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

public static Fragment getCurrentFragment(Activity activity) {
    FragmentManager fragmentManager = activity.getFragmentManager();
    if (fragmentManager.getBackStackEntryCount() > 0) {
        String lastFragmentName = fragmentManager.getBackStackEntryAt(
                fragmentManager.getBackStackEntryCount() - 1).getName();
        return fragmentManager.findFragmentByTag(lastFragmentName);
    }
    return null;
}

Убедитесь, что количество обратных стеков больше 0, иначе ArrayOutOfBoundsException может быть запущено во время выполнения. Если он не больше 0, верните значение null. Мы проверим значение null позже...

В-третьих, реализация в фрагменте

Внедрите интерфейс Backable в любом фрагменте, где вам необходимо переопределить поведение кнопки "Назад" . Добавьте метод реализации.

public class SomeFragment extends Fragment implements 
        FragmentManager.OnBackStackChangedListener, Backable {

...

    @Override
    public boolean onBackPressed() {

        // Logic here...
        if (backButtonShouldNotGoBack) {
            whateverMethodYouNeed();
            return true;
        }
        return false;
    }

}

В переопределении onBackPressed() введите любую логику, в которой вы нуждаетесь. Если вы хотите, чтобы кнопка "назад" на не удаляла задний стек (поведение по умолчанию), верните true, что ваше заднее событие было поглощено. В противном случае верните false.

Наконец, в вашей деятельности...

Переопределите метод onBackPressed() и добавьте к нему эту логику:

@Override
public void onBackPressed() {

    // Get the current fragment using the method from the second step above...
    Fragment currentFragment = NavUtils.getCurrentFragment(this);

    // Determine whether or not this fragment implements Backable
    // Do a null check just to be safe
    if (currentFragment != null && currentFragment instanceof Backable) {

        if (((Backable) currentFragment).onBackPressed()) {
            // If the onBackPressed override in your fragment 
            // did absorb the back event (returned true), return
            return;
        } else {
            // Otherwise, call the super method for the default behavior
            super.onBackPressed();
        }
    }

    // Any other logic needed...
    // call super method to be sure the back button does its thing...
    super.onBackPressed();
}

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

Второй вариант не включать активность

Иногда вы не хотите, чтобы Activity обрабатывала это вообще, и вам нужно обрабатывать его непосредственно внутри фрагмента. Но кто говорит, что не может иметь фрагменты с API обратной печати? Просто добавьте фрагмент в новый класс.

Создайте абстрактный класс, который расширяет фрагмент и реализует интерфейс View.OnKeyListner...

import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;

public abstract class BackableFragment extends Fragment implements View.OnKeyListener {

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.setFocusableInTouchMode(true);
        view.requestFocus();
        view.setOnKeyListener(this);
    }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_UP) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                onBackButtonPressed();
                return true;
            }
        }

        return false;
    }

    public abstract void onBackButtonPressed();
}

Как вы можете видеть, любой фрагмент, который расширяет BackableFragment, автоматически захватывает обратные клики с помощью интерфейса View.OnKeyListener. Просто позвоните абстрактному методу onBackButtonPressed() из внедренного метода onKey(), используя стандартную логику, чтобы распознать нажатие кнопки "Назад" . Если вам нужно зарегистрировать ключевые клики, отличные от кнопки "Назад" , просто не забудьте вызвать метод super при переопределении onKey() в вашем фрагменте, иначе вы отмените поведение в абстракции.

Прост в использовании, просто расширяйте и реализуйте:

public class FragmentChannels extends BackableFragment {

    ...

    @Override
    public void onBackButtonPressed() {
        if (doTheThingRequiringBackButtonOverride) {
            // do the thing
        } else {
            getActivity().onBackPressed();
        }
    }

    ...
}

Так как метод onBackButtonPressed() в суперклассе является абстрактным, после расширения вы должны реализовать onBackButtonPressed(). Он возвращает void, потому что ему просто нужно выполнить действие внутри класса фрагмента и не нужно передавать абсорбцию пресса обратно в Activity. Убедитесь, что вы вызываете метод Activity onBackPressed(), если все, что вы делаете с помощью кнопки "Назад" , не требует обработки, иначе кнопка "Назад" будет отключена... и вы не хочу этого!

ПредостереженияКак вы можете видеть, это устанавливает прослушиватель ключей в корневой вид фрагмента, и нам нужно будет сфокусировать его. Если в фрагменте есть какие-либо редактируемые тексты (или любые другие фокусы), которые расширяют этот класс (или другие внутренние фрагменты или представления, имеющие одинаковую), вам придется обрабатывать их отдельно. Там хорошая статья о расширении EditText, чтобы потерять фокус на обратном нажатии.

Я надеюсь, что кто-то найдет это полезным. Счастливое кодирование.

Ответ 9

Решение прост:

1) Если у вас есть класс базового фрагмента, который все фрагменты расширяются, добавьте в него этот класс, иначе создайте такой класс базового фрагмента

 /* 
 * called when on back pressed to the current fragment that is returned
 */
 public void onBackPressed()
 {
    // add code in super class when override
 }

2) В классе Activity переопределите onBackPressed следующим образом:

private BaseFragment _currentFragment;

@Override
public void onBackPressed()
{
      super.onBackPressed();
     _currentFragment.onBackPressed();
}

3) В классе "Фрагмент" добавьте требуемый код:

 @Override
 public void onBackPressed()
 {
    setUpTitle();
 }

Ответ 10

onBackPressed() вызывает отрыв фрагмента из Activity.

В ответ на @Sterling Diaz я думаю, что он прав. НО какая-то ситуация будет неправильной. (например, поворот экрана)

Итак, я думаю, мы могли бы определить, достигнуть ли isRemoving() целей.

Вы можете записать его в onDetach() или onDestroyView(). Это работа.

@Override
public void onDetach() {
    super.onDetach();
    if(isRemoving()){
        // onBackPressed()
    }
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    if(isRemoving()){
        // onBackPressed()
    }
}

Ответ 11

Хорошо, я сделал это так, и он работает для меня

Простой интерфейс

FragmentOnBackClickInterface.java

public interface FragmentOnBackClickInterface {
    void onClick();
}

Пример реализации

MyFragment.java

public class MyFragment extends Fragment implements FragmentOnBackClickInterface {

// other stuff

public void onClick() {
       // what you want to call onBackPressed?
}

то просто переопределите onBackPressed в действии

    @Override
public void onBackPressed() {
    int count = getSupportFragmentManager().getBackStackEntryCount();
    List<Fragment> frags = getSupportFragmentManager().getFragments();
    Fragment lastFrag = getLastNotNull(frags);
    //nothing else in back stack || nothing in back stack is instance of our interface
    if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
        super.onBackPressed();
    } else {
        ((FragmentOnBackClickInterface) lastFrag).onClick();
    }
}

private Fragment getLastNotNull(List<Fragment> list){
    for (int i= list.size()-1;i>=0;i--){
        Fragment frag = list.get(i);
        if (frag != null){
            return frag;
        }
    }
    return null;
}

Ответ 12

Вам следует добавить интерфейс к вашему проекту, как показано ниже:

public interface OnBackPressed {

     void onBackPressed();
}

И тогда вы должны реализовать этот интерфейс на своем фрагменте;

public class SampleFragment extends Fragment implements OnBackPressed {

    @Override
    public void onBackPressed() {
        //on Back Pressed
    }

}

И вы можете инициировать это событие onBackPressed под вашими действиями в событии onBackPressed, как показано ниже:

public class MainActivity extends AppCompatActivity {
       @Override
        public void onBackPressed() {
                Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
                if (currentFragment instanceof OnBackPressed) {  
                    ((OnBackPressed) currentFragment).onBackPressed();
                }
                super.onBackPressed();
        }
}

Ответ 13

Если вы используете EventBus, это, вероятно, гораздо более простое решение:

В вашем фрагменте:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    EventBus.getDefault().register(this);
}

@Override
public void onDetach() {
    super.onDetach();
    EventBus.getDefault().unregister(this);
}


// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    getSupportFragmentManager().popBackStack();
}

и в вашем классе Activity вы можете определить:

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    super.onBackPressed();
}

@Override
public void onBackPressed() {
    EventBus.getDefault().post(new BackPressedMessage(true));
}

BackPressedMessage.java - это просто объект POJO

Это супер чистое, и нет проблем с интерфейсом/реализацией.

Ответ 14

Это всего лишь небольшой код, который сделает трюк:

 getActivity().onBackPressed();

Надеюсь, это поможет кому-то:)

Ответ 15

это мое решение:

в MyActivity.java:

public interface OnBackClickListener {
        boolean onBackClick();
    }

    private OnBackClickListener onBackClickListener;

public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
        this.onBackClickListener = onBackClickListener;
    }

@Override
    public void onBackPressed() {
        if (onBackClickListener != null && onBackClickListener.onBackClick()) {
            return;
        }
        super.onBackPressed();
    }

и Фрагмент:

((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
    @Override
    public boolean onBackClick() {
        if (condition) {
            return false;
        }

        // some codes

        return true;
    }
});

Ответ 16

Как насчет использования onDestroyView()?

@Override
public void onDestroyView() {
    super.onDestroyView();
}

Ответ 17

@Override
public void onResume() {
    super.onResume();

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
                // handle back button
                replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);

                return true;
            }

            return false;
        }
    });
}

Ответ 18

Не используйте метод ft.addToBackStack(), чтобы при нажатии кнопки "Назад" ваша деятельность будет завершена.

proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

Ответ 19

Просто выполните следующие действия:

Всегда добавляя фрагмент,

fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();

Затем в основном действии переопределите onBackPressed()

if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
    getSupportFragmentManager().popBackStack();
} else {
    finish();
}

Чтобы обработать кнопку "Назад" в вашем приложении,

Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
    if (f != null) 
        getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()               
}

Что это!

Ответ 20

public class MyActivity 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();
    }
}

в свой фрагмент добавьте следующее, не забудьте реализовать интерфейс mainacctivity.

public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
         ((MyActivity) getActivity()).setOnBackPressedListener(this);
    }

@Override
public void doBack() {
    //BackPressed in activity will call this;
}

}

Ответ 21

Очень короткий и сладкий ответ:

getActivity().onBackPressed();

Объяснение всего сценария моего дела:

У меня есть FragmentA в MainActivity, Я открываю FragmentB из FragmentA (FragmentB является дочерним или вложенным фрагментом FragmentA)

 Fragment duedateFrag = new FragmentB();
 FragmentTransaction ft  = getFragmentManager().beginTransaction();
 ft.replace(R.id.container_body, duedateFrag);
 ft.addToBackStack(null);
 ft.commit();

Теперь, если вы хотите перейти в FragmentA из FragmentB, вы можете просто поместить getActivity().onBackPressed(); в FragmentB.

Ответ 22

В жизненном цикле деятельности всегда обратная кнопка Android обращается к транзакциям FragmentManager, когда мы использовали FragmentActivity или AppCompatActivity.

Чтобы обработать стопку назад, нам не нужно обрабатывать счетчик стоп-кадра или тег что-либо, но мы должны сохранить фокус при добавлении или замене фрагмента. Пожалуйста, найдите следующие фрагменты, чтобы обрабатывать обратные кнопки,

    public void replaceFragment(Fragment fragment) {

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (!(fragment instanceof HomeFragment)) {
            transaction.addToBackStack(null);
        }
        transaction.replace(R.id.activity_menu_fragment_container, fragment).commit();
    }

Здесь я не буду добавлять стопку для моего домашнего фрагмента, потому что это главная страница моего приложения. Если добавить addToBackStack в HomeFragment, то приложение будет ждать, чтобы удалить все frament в acitivity, тогда мы получим пустой экран, поэтому я соблюдаю следующее условие:

if (!(fragment instanceof HomeFragment)) {
            transaction.addToBackStack(null);
}

Теперь вы можете увидеть ранее добавленный фрагмент на acitvity, и приложение выйдет при достижении HomeFragment. вы также можете посмотреть следующие фрагменты.

@Override
public void onBackPressed() {

    if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
        closeDrawer();
    } else {
        super.onBackPressed();
    }
}

Ответ 23

Согласно примечаниям к выпуску AndroidX, androidx.activity 1.0.0-alpha01 выпущен и представляет ComponentActivity, новый базовый класс существующих FragmentActivity и AppCompatActivity. И этот релиз приносит нам новую функцию:

Теперь вы можете зарегистрировать OnBackPressedCallback через addOnBackPressedCallback для получения onBackPressed() вызовов onBackPressed() без необходимости переопределять метод в вашей деятельности.

Ответ 24

Вы можете зарегистрировать фрагмент в действии, чтобы справиться с прессой:

interface BackPressRegistrar {
    fun registerHandler(handler: BackPressHandler)
    fun unregisterHandler(handler: BackPressHandler)
}

interface BackPressHandler {
    fun onBackPressed(): Boolean
}

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

Во фрагменте:

private val backPressHandler = object : BackPressHandler {
    override fun onBackPressed(): Boolean {
        showClosingWarning()
        return false
    }
}

override fun onResume() {
    super.onResume()
    (activity as? BackPressRegistrar)?.registerHandler(backPressHandler)
}

override fun onStop() {
    (activity as? BackPressRegistrar)?.unregisterHandler(backPressHandler)
    super.onStop()
}

В деятельности:

class MainActivity : AppCompatActivity(), BackPressRegistrar {


    private var registeredHandler: BackPressHandler? = null
    override fun registerHandler(handler: BackPressHandler) { registeredHandler = handler }
    override fun unregisterHandler(handler: BackPressHandler) { registeredHandler = null }

    override fun onBackPressed() {
        if (registeredHandler?.onBackPressed() != false) super.onBackPressed()
    }
}

Ответ 25

Лучшее решение,

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;

public class BaseActivity extends AppCompatActivity {
    @Override
    public void onBackPressed() {

        FragmentManager fm = getSupportFragmentManager();
        for (Fragment frag : fm.getFragments()) {
            if (frag == null) {
                super.onBackPressed();
                finish();
                return;
            }
            if (frag.isVisible()) {
                FragmentManager childFm = frag.getChildFragmentManager();
                if (childFm.getFragments() == null) {
                    super.onBackPressed();
                    finish();
                    return;
                }
                if (childFm.getBackStackEntryCount() > 0) {
                    childFm.popBackStack();
                    return;
                }
                else {

                    fm.popBackStack();
                    if (fm.getFragments().size() <= 1) {
                        finish();
                    }
                    return;
                }

            }
        }
    }
}

Ответ 26

Это просто, если у вас есть A Activity A, и вы делаете 3 фрагмента, такие как B, C и D. Теперь, если вы находитесь в фрагменте B или C и onBackPressed, вы хотите каждый раз перемещаться по фрагменту D. просто переопределить метод onBackPressed() в основном действии A, а также при переходе к любому фрагменту, затем передайте TAG или имя этого фрагмента, с помощью которого вы узнали этот фрагмент в основном действии A.

Я приводил пример того, с помощью которого вы можете легко понять, что....

if (savedInstanceState == null) {

   getSupportFragmentManager().beginTransaction().add(R.id.container, new C_fragment(),"xyz").commit();

}

или если вы переходите от фрагмента B к фрагменту C.. и нажимаете назад, вы хотите выйти на фрагмент D... как ниже

btn.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View view) {

        getActivity().getSupportFragmentManager().beginTransaction().add(R.id.container, new C_frament(), "xyz").commit();
        ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Fragment C");
    }
});

Теперь вам нужно просто переопределить метод onBackPressed() в основной активности... как показано ниже.

@Override
public void onBackPressed() {
    FragmentManager fragmentManager =getSupportFragmentManager();
    if (((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")) != null && ((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")).isVisible()) {
        Fragment fragment = new D_Fragment();
        fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
        getSupportActionBar().setTitle("D fragment ");
    } else {
        super.onBackPressed();
    }
}

Ответ 27

Я использовал другой подход следующим образом:

  • шина событий Otto для связи между Activity и его фрагментами
  • Стек в Activity, содержащий пользовательские обратные действия, завернутые в Runnable, который определяет вызывающий фрагмент
  • Когда в управляющей активности вызывается onBackPressed, она выдает самое последнее пользовательское обратное действие и выполняет его Runnable. Если в стеке ничего нет, по умолчанию super.onBackPressed() вызывается

Полный подход с примером кода включен здесь в качестве ответа на этот другой вопрос SO.

Ответ 28

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

В вашей деятельности установите OnPageChangeListener для ViewPager, чтобы вы знали, когда пользователь находится во втором действии. Если он находится во втором действии, сделайте логическое true следующим образом:

    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);
    mViewPager.setCurrentItem(0);
    mViewPager.addOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // TODO Auto-generated method stub
                mSectionsPagerAdapter.instantiateItem(mViewPager, position);
                if(position == 1)
                    inAnalytics = true;
                else if(position == 0)
                    inAnalytics = false;
        }

        @Override
        public void onPageScrolled(int position, float arg1, int arg2) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
            // TODO Auto-generated method stub

        }
    });

Теперь проверяем логическое значение, когда нажимаем кнопку "Назад", и устанавливаем текущий элемент в свой первый фрагмент:

@Override
public void onBackPressed() {
    if(inAnalytics)
        mViewPager.setCurrentItem(0, true);
    else 
        super.onBackPressed();
}

Ответ 29

Фрагмент: Сделайте BaseFragment, разместив метод:

 public boolean onBackPressed();

Активность:

@Override
public void onBackPressed() {
    List<Fragment> fragments = getSupportFragmentManager().getFragments();
    if (fragments != null) {
        for (Fragment fragment : fragments) {
            if (!fragment.isVisible()) continue;

            if (fragment instanceof BaseFragment && ((BaseFragment) fragment).onBackPressed()) {
                return;
            }
        }
    }

    super.onBackPressed();
}

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

Ответ 30

Хорошо, ребята, я наконец нашел хорошее решение.

В вашей функции onCreate() в вашей работе, в которой ваши фрагменты добавят слушателя с заменой backstack следующим образом:

    fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            List<Fragment> f = fragmentManager.getFragments();
            //List<Fragment> f only returns one value
            Fragment frag = f.get(0);
            currentFragment = frag.getClass().getSimpleName();
        }
    });

(Также добавление моего fragmenManager объявляется в действия O Теперь каждый раз, когда вы меняете фрагмент, текущий фрагмент String станет именем текущего фрагмента. Затем в действиях onBackPressed() вы можете управлять действиями вашей кнопки возврата так:

    @Override
    public void onBackPressed() {

    switch (currentFragment) {
        case "FragmentOne":
            // your code here
            return;
        case "FragmentTwo":
            // your code here
            return;
        default:
            fragmentManager.popBackStack();
            // default action for any other fragment (return to previous)
    }

}

Я могу подтвердить, что этот метод работает для меня.