【问题标题】:App exits on presing back button inside fragments within navigation drawer应用程序在导航抽屉内的片段内按下返回按钮时退出
【发布时间】:2014-12-28 12:43:01
【问题描述】:

当我尝试从子片段移动到父片段时,我的应用程序退出(它不会崩溃)。这里 LandingActivity.java 是我调用片段 ChannelGrid.java 的主要活动,它调用片段 GridMain.java。当我在片段GridMain应用程序退出而不是移动到ChannelGrid.java中按下移动设备的后退按钮。我已将addToBackStack(“tag”)添加到片段并尝试使用onKey()..我也在不同设备上测试了我的应用程序..我检查了找出具有相同问题的其他解决方案并尝试了它们,但没有任何效果..

导航抽屉-LandingActivity.java-ChaanelGrid.java(Fragment)-GridMain.java(Fragment)

LandingActivity.java

   currentFragment = new ChaanelGrid();

                currentFragment.setArguments(args);
                frgManager = getFragmentManager();

                frgManager.beginTransaction().add(R.id.content_frame, currentFragment).addToBackStack("tag")
                        .commit();

ChaanelGrid.java

Fragment currentFragment = new GridMain();



                    FragmentManager frgManager;
                    frgManager = getFragmentManager();
                    frgManager.beginTransaction().add(R.id.content_frame, currentFragment).addToBackStack("GridMain")
                            .commit()

GridMain.java(我也试过不使用 onKey() 方法但没有用)

rootView.setOnKeyListener(new View.OnKeyListener() {


   @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK)
            {
                Fragment currentFragment = new ChaanelGrid();


                FragmentManager frgManager;
                frgManager = getFragmentManager();
                frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
                        .commit();
                return true;
            }

logcat 详细

   10-31 21:46:57.954  24452-24452/D/ActivityThread﹕ ACT-AM_ON_PAUSE_CALLED ActivityRecord{41eb8b98 token=android.os.BinderProxy@41bb9828 {xyz/xyz..activity.LandingActivity_}}
10-31 21:46:57.971  24452-24452/ D/ActivityThread﹕ ACT-PAUSE_ACTIVITY_FINISHING handled : 0 / android.os.BinderProxy@41bb9828
10-31 21:46:58.007  24452-24452/ V/InputMethodManager﹕ focusOut: android.widget.GridView@41f06f40 mServedView=android.widget.GridView@41f06f40 winFocus=false
10-31 21:46:58.297  24452-24452/ I/SurfaceTextureClient﹕ [0x5143bc58] frames:44, duration:1.002000, fps:43.883736
10-31 21:46:58.350  24452-24452/ D/OpenGLRenderer﹕ Flushing caches (mode 0)
10-31 21:46:58.432  24452-24452/ D/OpenGLRenderer﹕ Flushing caches (mode 0)
10-31 21:46:58.753  24452-24452/ D/OpenGLRenderer﹕ Flushing caches (mode 0)
10-31 21:46:58.754  24452-24452/ D/OpenGLRenderer﹕ Flushing caches (mode 0)
10-31 21:46:58.755  24452-24452/ D/OpenGLRenderer﹕ Flushing caches (mode 2)
10-31 21:46:58.879  24452-24452/ D/ActivityThread﹕ ACT-DESTROY_ACTIVITY handled : 1 / android.os.BinderProxy@41bb9828

我尝试在 LandingActivity.java 中添加以下内容

@Override

public void onBackPressed() {
    FragmentManager frgManager;
    frgManager = getFragmentManager();

    Fragment fragment = fragmentManager.findFragmentByTag("GridMain");
    if (fragment != null) {
        GridMain gridMain = (GridMain) fragment;
        if (!gridMain.onBackPressed()) {
            super.onBackPressed();
        }
    }
    else {
        super.onBackPressed();
    }
}

并在 GridMain.java 中跟随

   protected boolean onBackPressed() {
        FragmentManager frgManager;
        frgManager = getFragmentManager();
        frgManager.popBackStack();
        return true;
    }

使用日志我检查了 LandingActivity.java 的 onBackPressed() 是否被调用,但输出仍然相同..

【问题讨论】:

  • 默认情况下(如果未处理),后退按钮会从主 Activity 退出。假设 LandingActivity 是您的主要 Activity 并且您在其中操作 Fragmen,您必须处理 Back 按钮按下以根据当前 Fragment 替换活动的 Fragment。
  • @Funkystein 我明白你所说的......请通过检查我尝试过的上述代码让我知道我哪里出错了。
  • @Funkystein 通过日志我检查了它是否在按下后退按钮时调用了 LandingActivity 的 onBackPressed() 方法,但应用程序正在退出..我放在 onBackPressed() 中的代码是否有任何问题LandingActivity的方法
  • 查看我的回答,了解我通常的做法。

标签: android android-fragments back-button


【解决方案1】:

这就是我解决它的方法..当您在片段中按下后退按钮时,如果您已声明,您的活动的 onBackPressed() 方法将被调用..因此,在导航抽屉中处理片段的后退按钮可以是其中之一方式..

主要活动

     public static boolean isMainActivityShown ;
     public static boolean isFragment1Shown=false ;
     public static boolean isFragment2Shown=false ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        isMainActivityShown=true  //inside onCreate method put isMainActivityShown true
        . 
        . 
        .
        {
        Fragment currentFragment = new Fragment1();
        isMainActivityShown=false;   //when moving to fragment1 
        isFragment1Shown=true;
        frgManager = getFragmentManager();
        frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
                                        .commit();
        }
        .
        .
        }
     @Override
        public void onBackPressed() {

            if(isMainActivityShown)
            {
                finish();
            }
            else if(isFragment1Shown)
            {
               //write the code to handle back button when you are in Fragment1
            }
           else if(isFragment2Shown)
            {  //When you are in Fragment 2 pressing back button will move to fragment1
                Fragment currentFragment = new Fragment1();
                isFragment2Shown=false;
                isFragment1Shown=true;

                FragmentManager frgManager;
                frgManager = getFragmentManager();
                frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
                        .commit();
            }

            }

片段1

Fragment currentFragment = new Fragment2();
MainActivity.isFragment1Shown=false;
MainActivity.isFragment2Shown=true;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
                                    .commit();

【讨论】:

    【解决方案2】:

    我尝试了这里建议的所有解决方案,但没有一个对我有用。 这就是我最终通过修改投票最高的答案来解决它的方法:

    在托管片段的活动中,声明 FragmentManager

    private FragmentManager fragmentManager;
    

    在你的 onCreateMethod 中初始化它:

    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
    
      fragmentManager = getFragmentManager();
      ...
    

    最后,在你的 onBackPressed 方法中这样做:

     public void onBackPressed() {
        if(fragmentManager.getBackStackEntryCount() != 0) {
            fragmentManager.popBackStack();
            if (IS_MAIN_SHOWN) {
                finish();
            } else  {
                displayView(0);  //this is the method that changes the fragments, takes an int argument for the position of the fragment.
            }
    
        } else {
            super.onBackPressed();
        }
    }
    

    【讨论】:

      【解决方案3】:

      我建议使用 TAG 的片段替换来产生相同的结果。

      简单例子如下图

      使用 TAG 将片段 B 添加到活动中

      fragmentTransaction.replace(R.id.main_fragment_container, new FragmentB(),"TAG_B");

      Fragment A -> Fragment B [onBackPressed] -->Fragment A 覆盖 Activity 文件中的 onBackPressed() ,

      // 检查片段 B 并且您正在查看片段 B

      如果 (getSupportFragmentManager().findFragmentByTag("TAG_B")!=null) { fragmentTransaction.replace(R.id.main_fragment_container, new FragmentA(),"TAG_A");

      }

      【讨论】:

        【解决方案4】:

        这就是我通常处理后退按钮的方式:

        // "State Machine" variables: to indicate which is the active Fragment.
        private static boolean isHelpShown = false;
        protected static boolean isInfoShown = false;
        protected static boolean isMainShown = false;
        private static boolean isViewShown = false;
        
        // Used to switch between Fragments.
        private static enum Fragments
        {
            MAIN,
            VIEW,
            HELP,
            INFO
        }
        
        @Override
        public final void onBackPressed()
        {
            if (isMainShown)
            {
                // We're in the MAIN Fragment.
                finish();
            }
            else
            {
                // We're somewhere else, reload the MAIN Fragment.
                showFragment(Fragments.MAIN);
            }
        }
        
        private final void showFragment(final Fragments FragmentType)
        {
            isViewShown = false;
            isHelpShown = false;
            isInfoShown = false;
            isMainShown = false;
        
            final FragmentTransaction ft =
                getSupportFragmentManager().beginTransaction();
        
            /*
            Replace whatever is in the fragment_container view with this
            fragment, and add the transaction to the back stack so the user can
            navigate back.
            */
            switch(FragmentType)
            {
                case HELP:
                {
                    ft.replace(R.id.frgMaster, new FRG_Help());
                    isHelpShown = true;
                    break;
                }
                case INFO:
                {
                    ft.replace(R.id.frgMaster, new FRG_Info());
                    isInfoShown = true;
                    break;
                }
                case VIEW:
                {
                    ft.replace(R.id.frgMaster, new FRG_View());
                    isViewShown = true;
                    break;
                }
                case MAIN:
                {
                    ft.replace(R.id.frgMaster, new FRG_Main());
                    isMainShown = true;
                    break;
                }
            }
        
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        
            // Finalize the transaction...
            ft.commit();
        
            getSupportFragmentManager().executePendingTransactions();
        }
        

        如您所见,出于我的需要,我只在我们处于主片段(我退出)或不在时(我回到主片段:再次按下后退出)处理。

        您可以在 onBackPressed 方法中添加更多检查,以检查您是否在另一个 Fragment 中并相应地加载另一个。

        【讨论】:

        • 这里 FRG_View、FRG_Main 等是你的片段。你是否也在各自的片段中设置 isHelpShown、isInfoShown 的值。例如,如果我在片段 FRG_Help() 中,那么我需要设置isHelpShown 的值为 true ..
        • 否,因为 onBackPressed 仅在主 Activity 中有效。无需通知您的 Fragment 他是活跃的。 Activity 知道哪个 Fragment 处于活动状态,这就足够了。
        • 感谢 Funkystein..u 可以在下面查看我的答案,我是如何在您的指导下解决的..
        • 很高兴知道我是你的指路明灯。 ;)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-11
        • 1970-01-01
        相关资源
        最近更新 更多