首页 文章

如何在Fragments中实现onBackPressed()?

提问于
浏览
343

有没有一种方法可以在Android Fragment中实现 onBackPressed() ,类似于我们在Android Activity中实现的方式?

由于Fragment生命周期没有 onBackPressed() . 有没有其他替代方法来覆盖Android 3.0碎片中的 onBackPressed()

30 回答

  • 71

    我以这种方式解决了在Activity中覆盖 onBackPressed 的问题 . 在提交之前 FragmentTransaction 都是 addToBackStack

    @Override
    public void onBackPressed() {
    
        int count = getFragmentManager().getBackStackEntryCount();
    
        if (count == 0) {
            super.onBackPressed();
            //additional code
        } else {
            getFragmentManager().popBackStack();
        }
    
    }
    
  • 19

    根据@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 及其片段

    • 在 class 上创建私人监听器 BaseActivity

    protected OnBackPressedListener onBackPressedListener;
    
    • create方法在 BaseActivity 中设置监听器
    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }
    
    • in override 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;
    }
    

    瞧,现在当你点击片段时,你应该 grab 你的自定义背面方法 .

  • 1

    这对我有用:https://stackoverflow.com/a/27145007/3934111

    @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's click listener
                    return true;
                }
                return false;
            }
        });
    }
    
  • 37

    我认为最好的解决方案是

    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;
            }
        }
    }
    

    KOTLIN SOLUTION

    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
            }
        }
    }
    
  • 2

    如果您想要这种功能,则需要在活动中覆盖它,然后在所有片段中添加 YourBackPressed 接口,只要按下后退按钮,就会调用相关片段 .

    编辑:我想追加我之前的回答 .

    如果我今天要这样做,我会使用广播,或者如果我希望其他面板同时更新到主/主内容面板,则可以使用有序广播 .

    支持库中的LocalBroadcastManager可以为此提供帮助,您只需在 onBackPressed 中发送广播并订阅您关注的片段 . 我认为Messaging是一个更加分离的实现,并且可以更好地扩展,所以它现在是我的官方实现建议 . 只需使用 Intent 的操作作为邮件的过滤器 . 发送新创建的 ACTION_BACK_PRESSED ,从您的活动中发送它并在相关片段中收听它 .

  • 0

    这些都不容易实现,也不会以最佳方式运行 .

    片段有一个方法调用onDetach来完成这项工作 .

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

    这将是工作 .

  • 3

    只需在您的片段之间转换时添加 addToBackStack ,如下所示:

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

    如果您编写 addToBackStack(null) ,它将自行处理它,但如果您提供标记,则应手动处理 .

  • 21

    由于这个问题和一些答案已经超过五年了,让我分享一下我的解决方案 . 这是对@oyenigun的回答的后续和现代化

    UPDATE: 在本文的底部,我添加了一个使用抽象Fragment扩展的替代实现,它根本不涉及Activity,这对于任何具有更复杂的片段层次结构的人来说都是有用的,这些片段层次结构涉及需要不同反向行为的嵌套片段 .

    我需要实现这个,因为我使用的一些片段具有较小的视图,我想用后退按钮解除,例如弹出的小信息视图等,但这对于需要覆盖行为的任何人都有好处 . 片段内的后退按钮 .

    First, define an Interface

    public interface Backable {
        boolean onBackPressed();
    }
    

    这个接口,我称之为 Backable (我是命名约定的坚持者),它有一个必须返回 boolean 值的方法 onBackPressed() . 我们需要强制执行一个布尔值,因为我们需要知道后退按钮是否有"absorbed"返回事件 . 返回 true 表示它有,并且不需要进一步操作,否则, false 表示仍然必须执行默认的后退操作 . 该接口应该是它自己的文件(最好是在一个名为 interfaces 的独立包中) . 请记住,将类分成包是很好的做法 .

    Second, find the top fragment

    我创建了一个返回的方法后堆栈中的最后一个 Fragment 对象 . 我使用标签...如果您使用ID 's, make the necessary changes. I have this static method in a utility class that deals with navigation states, etc... but of course, put it where it best suits you. For edification, I' ve将我的名字放在一个名为 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 . 如果它不是't greater than 0, return null. We' ll稍后检查一个空值...

    Third, Implement in a Fragment

    在需要覆盖后退按钮行为的任何片段中实现 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 .

    Lastly, in your Activity...

    覆盖 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() 并可以返回 . 否则,将其视为正常的背压并调用超级方法 .

    Second Option to not involve the Activity

    有时,您根本不希望Activity处理此问题,您需要在片段中直接处理它 . 但谁说你 can't 有片段与背压API?只需将您的片段扩展到一个新类 .

    创建一个扩展Fragment并实现 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 界面自动捕获返回的点击次数 . 只需在实现的 onKey() 方法中使用标准逻辑调用抽象 onBackButtonPressed() 方法,即可识别后退按钮 . 如果你需要注册后退按钮以外的关键点击,只需确保在覆盖片段中的 onKey() 时调用 super 方法,否则你将覆盖抽象中的行为 .

    简单易用,只需扩展和实现:

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

    由于超类中的 onBackButtonPressed() 方法是抽象的,因此一旦扩展,就必须实现 onBackButtonPressed() . 它返回 void 因为它只需要在片段类中执行一个动作,并且不需要将按下的吸收传递回Activity . Make sure 如果您需要处理的话,您可以调用Activity onBackPressed() 方法,否则后退按钮将被禁用...而您不希望这样!

    Caveats 正如您所看到的,这会将关键侦听器设置为片段的根视图,我们需要单独处理它 . 关于extending an EditText的一篇好文章将失去对新闻的关注 .

    我希望有人觉得这很有用 . 快乐的编码 .

  • 6

    解决方案很简单:

    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)在Fragment类中,添加所需的代码:

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

    Just follow these steps: 总是在添加片段时

    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()               
    }
    

    而已!

  • 251

    好吧,我这样做了,它对我有用

    简单的界面

    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;
    }
    
  • 86

    onBackPressed() 原因片段与活动分离 .

    根据@Sterling Diaz的回答,我认为他是对的 . 但有些情况会出错 . (例如旋转屏幕)

    所以,我认为我们可以检测是否 isRemoving() 实现目标 .

    你可以写在 onDetach()onDestroyView() . 这是工作 .

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

    您应该像下面一样为项目添加界面;

    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();
            }
    }
    
  • 1

    如果您使用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对象

    这是超级干净的,没有接口/实现麻烦 .

  • 13

    使用onDestroyView()怎么样?

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

    这只是一个小代码,可以解决这个问题:

    getActivity().onBackPressed();
    

    希望它可以帮助别人:)

  • 2

    这是我的解决方案:

    在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;
        }
    });
    
  • 7
    @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;
            }
        });
    }
    
  • 5

    不要实现ft.addToBackStack()方法,以便当您按下后退按钮时,您的活动将完成 .

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

    简短而甜蜜的回答:

    getActivity().onBackPressed();
    

    我的案例的整个场景的解释:

    我在MainActivity中有FragmentA,我从FragmentA打开FragmentB(FragmentB是FragmentA的子片段或嵌套片段)

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

    现在,如果你想从FragmentB转到FragmentA,你可以简单地将 getActivity().onBackPressed(); 放在FragmentB中 .

  • 7

    最佳方案,

    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;
                    }
    
                }
            }
        }
    }
    
  • 3

    在活动生命周期中,当我们使用FragmentActivity或AppCompatActivity时,总是android后退按钮处理FragmentManager事务 .

    要处理后台堆栈,我们不需要处理其后台堆栈计数或标记任何内容,但我们应该在添加或替换片段时保持焦点 . 请找到以下代码片段来处理后退按钮的情况,

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

    在这里,我不会为我的home片段添加堆栈,因为它是我的应用程序的主页 . 如果将addToBackStack添加到HomeFragment,那么应用程序将等待删除活动中的所有片段,然后我们将获得空白屏幕,因此我保持以下条件,

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

    现在,您可以看到之前在活动中添加的片段,app将在到达HomeFragment时退出 . 您还可以查看以下代码段 .

    @Override
    public void onBackPressed() {
    
        if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
            closeDrawer();
        } else {
            super.onBackPressed();
        }
    }
    
  • 1

    它很简单,如果你有一个活动A并且你制作了3个片段,如B,C和D.Now如果你在片段B或C和 onBackPressed 你想每次都在片段D上移动 . 那么你必须只是覆盖 onBackPressed() 主Activity A中的方法,当你跳转到任何片段然后传递该片段的 TAG or name 时,您通过该片段识别主Activity 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();
        }
    }
    
  • 3

    我使用了另一种方法如下:

    • Otto event bus在活动及其碎片之间进行通信

    • 活动中的堆栈,包含调用片段定义的 Runnable 中包含的自定义后退操作

    • 当在控制活动中调用 onBackPressed 时,它会弹出最近的自定义后退操作并执行其 Runnable . 如果堆栈中没有任何内容,则调用默认的 super.onBackPressed()

    包含示例代码的完整方法包含here作为this other SO question的答案 .

  • 1

    公共类MyActivity扩展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();
    }
    

    }

    在你的片段中添加以下内容,不要忘记实现mainactivity的界面 .

    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;
    }
    
    }
    
  • 7

    我知道现在为时已晚,但我上周遇到了同样的问题 . 没有一个答案对我有帮助 . 然后我正在玩代码,这很有效,因为我已经添加了片段 .

    在您的活动中,为 ViewPager 设置 OnPageChangeListener ,以便您知道用户何时处于第二个活动中 . 如果他在第二个活动中,请按如下方式创建一个布尔 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();
    }
    
  • 64

    好的,我终于找到了一个很好的解决方案 .

    在您的活动中的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)
        }
    
    }
    

    我可以确认这种方法适合我 .

  • 0

    我有同样的问题,我为它创建了一个新的监听器,并在我的片段中使用 .

    1 - 您的活动应该有一个监听器接口和一个监听器列表

    2 - 您应该实现添加和删除侦听器的方法

    3 - 您应该覆盖onBackPressed方法以检查是否有任何侦听器使用了反压

    public class MainActivity ... {
    
        /**
         * Back press listener list. Used for notifying fragments when onBackPressed called
         */
        private Stack<BackPressListener> backPressListeners = new Stack<BackPressListener>();
    
    
        ...
    
        /**
         * Adding new listener to back press listener stack
         * @param backPressListener
         */
        public void addBackPressListener(BackPressListener backPressListener) {
            backPressListeners.add(backPressListener);
        }
    
        /**
         * Removing the listener from back press listener stack
         * @param backPressListener
         */
        public void removeBackPressListener(BackPressListener backPressListener) {
            backPressListeners.remove(backPressListener);
        }
    
    
        // Overriding onBackPressed to check that is there any listener using this back press
        @Override
        public void onBackPressed() {
    
            // checks if is there any back press listeners use this press
            for(BackPressListener backPressListener : backPressListeners) {
                if(backPressListener.onBackPressed()) return;
            }
    
            // if not returns in the loop, calls super onBackPressed
            super.onBackPressed();
        }
    
    }
    

    4 - 您的片段必须实现背压接口

    5 - 您需要将片段添加为背压的监听器

    6 - 如果片段使用此反压,则应从onBackPressed返回true

    7 - 重要 - 您必须从列表onDestroy中删除该片段

    public class MyFragment extends Fragment implements MainActivity.BackPressListener {
    
    
        ...
    
        @Override
        public void onAttach(Activity activity) {
            super.onCreate(savedInstanceState);
    
            // adding the fragment to listener list
            ((MainActivity) activity).addBackPressListener(this);
        }
    
        ...
    
        @Override
        public void onDestroy() {
            super.onDestroy();
    
            // removing the fragment from the listener list
            ((MainActivity) getActivity()).removeBackPressListener(this);
        }
    
        ...
    
        @Override
        public boolean onBackPressed() {
    
            // you should check that if this fragment is the currently used fragment or not
            // if this fragment is not used at the moment you should return false
            if(!isThisFragmentVisibleAtTheMoment) return false;
    
            if (isThisFragmentUsingBackPress) {
                // do what you need to do
                return true;
            }
            return false;
        }
    }
    

    使用Stack而不是ArrayList能够从最新的片段开始 . 将片段添加到后台堆栈时也可能存在问题 . 因此,在使用背压时,您需要检查片段是否可见 . 否则其中一个片段将使用该事件,并且最新片段将不会在后退时关闭 .

    我希望这能解决每个人的问题 .

  • 1

    在mainActivity上

    protected DrawerHomeActivity.OnBackPressedListener onBackPressedListener;
    
    public interface OnBackPressedListener {
        void doBack();
    }
    
    public void setOnBackPressedListener(DrawerHomeActivity.OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }
    
    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null) {
            onBackPressedListener.doBack();
    
    
        }
        else
            super.onBackPressed();
    
    
    
    }
    

    片段实现基本活动/片段之类的

    implements DrawerHomeActivity.OnBackPressedListener
    

    DraweHomeActivity是我的基础活动写作

    ((DrawerHomeActivity) getActivity()).setOnBackPressedListener(this);
    

    并创建方法doBack

    @Override
    public void doBack() {
        //call base fragment 
        }
    
  • 6

    Fragment: 使BaseFragment放置一个方法:

    public boolean onBackPressed();
    

    Activity:

    @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'(意味着它已被处理,因此没有进一步的操作)时中止 .

相关问题