5

My app exits when i try to move from child fragment to parent fragment(it doesn't crashes).Here LandingActivity.java is main activity in which I am calling fragment ChannelGrid.java which calls fragment GridMain.java.When i presses back button of mobile in fragment GridMain app exits rather than moving to ChannelGrid.java.I have added addToBackStack("tag") to fragments and also tried using onKey()..I tested my app on different devices also..I checked out other solutions with same issue and tried them but nothing works..

Navigation Drawer-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(i tried without onKey() method also but didn't worked)

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 verbose

   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

I tried adding following in 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();
    }
}

and following in GridMain.java

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

Using Log i checked tht onBackPressed() of LandingActivity.java is being called but still the same output..

Android Developer
  • 9,157
  • 18
  • 82
  • 139
  • By default (if not handled) the Back button exits from the main Activity. Assuming that LandingActivity is your main Activity and you manipulate Fragmens inside it, you have to handle the Back button presses in order to replace the active Fragment basing on the current one. – Phantômaxx Nov 01 '14 at 09:18
  • @Funkystein i understand what u said.. plzz let me know where i am going wrong by checking above code which i have tried. – Android Developer Nov 01 '14 at 09:29
  • @Funkystein through log i checked that its calling the onBackPressed() method of LandingActivity on pressing back button yet the app is exiting..is there any problem in the code which i have placed inside onBackPressed() method of LandingActivity – Android Developer Nov 01 '14 at 09:32
  • See my answer on how I normally do. – Phantômaxx Nov 01 '14 at 09:41

4 Answers4

4

This is how I solved it..When you press back button inside your fragment onBackPressed() method of your activity will be called if you have declared that..So handling back button for fragments within navigation drawer can be one in this way..

MainActvity

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

            }

Fragment1

Fragment currentFragment = new Fragment2();
MainActivity.isFragment1Shown=false;
MainActivity.isFragment2Shown=true;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
                                    .commit();
Android Developer
  • 9,157
  • 18
  • 82
  • 139
3

This is how I normally handle the Back Button:

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

As you can see, for my needs I only handle when we're in the MAIN Fragment (I quit) or when we aren't (I go back to the MAIN Fragment: another Back press and it quits).

You can add more checks in the onBackPressed method to check if you are in another Fragment and load another one, accordingly.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
  • Here FRG_View,FRG_Main etc are your fragments..are u setting the values of isHelpShown,isInfoShown in their respective fragments also..For example if i am in fragment FRG_Help() then i need to set the value of isHelpShown true there.. – Android Developer Nov 01 '14 at 09:57
  • No, because onBackPressed **only works in the main Activity**. There's no need to inform your Fragment that he is the active one. The Activity knows which Fragment is active and that's enough. – Phantômaxx Nov 01 '14 at 10:10
  • 1
    Thanks Funkystein..u can check my answer below how i solved it with your guidance.. – Android Developer Nov 01 '14 at 11:09
  • Glad to know I was a guiding ray for you. ;) – Phantômaxx Nov 01 '14 at 11:43
0

I will suggest using the fragment replacement with TAG to produce the same result .

Simple example as shown below

Add the fragment B to activity with TAG

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

Fragment A -> Fragment B [onBackPressed] -->Fragment A Override the onBackPressed() in the Activity files where ,

// check for fragment B and you are viewing fragment B

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

}

0

I tried all of the solutions suggested here , but none worked for me. This is how I finally solved it by modifying the highest voted answer:

In the activity hosting the fragments, declare FragmentManager

private FragmentManager fragmentManager;

initialize it in your onCreateMethod:

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

  fragmentManager = getFragmentManager();
  ...

Finally, in your onBackPressed method do this:

 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();
    }
}
Ojonugwa Jude Ochalifu
  • 26,627
  • 26
  • 120
  • 132