Back Press for the View In Fragment

449 views Asked by At

My problem is something similar like this. I am working in Skobbler map. I have MainActivity which include HomeFragment. My HomeFragement includes the stack of view like: A->B->C->D. When I reach to the view D, if I back press then I want to go back like: D->-C->B->A.

In my MainActivity, I include the Fragment in onCreate method:

homeFragment = HomeFragment.newInstance();
    getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.llMainActivityContainer, homeFragment)
            .addToBackStack(TAG)
            .commit();

and

@Override
public void onBackPressed() {
    if (!homeFragment.onBackPressed()) {
        int count = getSupportFragmentManager().getBackStackEntryCount();
        if (count > 0) {
            getSupportFragmentManager().popBackStack();
            return;
        }
        super.onBackPressed();
    }
}

In my HomeFragment, I have onBackPress method.

public boolean onBackPressed() {}

But, I am unable to come back from final view to first view as homescreen. What should I include here? What can be done to solve this problem?

Add Code

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rlHomeContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">


<com.skobbler.ngx.map.SKMapViewHolder
    android:id="@+id/skmVHHome"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<RelativeLayout
    android:id="@+id/chess_board_background"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/map_background" />

<include layout="@layout/layout_driving_direction_info" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fabDrivingDirections"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@+id/fabCurrentLoc"
    android:layout_alignParentRight="true"
    android:layout_marginBottom="16dp"
    android:layout_marginRight="@dimen/activity_horizontal_margin"
    app:backgroundTint="@color/blue_panel_day_background" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fabCurrentLoc"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:layout_marginBottom="150dp"
    android:layout_marginRight="@dimen/activity_horizontal_margin"
    app:backgroundTint="@color/blue_panel_day_background" />


<include
    layout="@layout/layout_drive_info"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true" />


</RelativeLayout>
1

There are 1 answers

0
kris larson On

It feels like Google missed this part when designing the fragment classes for tablets. Fragments may have an interest in handling the back button, but they don't receive any type of callback to let them know the back button was pressed.

This is how I solved that problem.

  • Define an interface. I did this as an inner interface of the activity since it's the activity that accesses those clients that implement it.

        public interface HandlesOnBackPressed {
    
            /**
             * Callback for back button pressed event.
             * @return true if the back press was handled so the activity doesn't need to.
             */
            boolean onBackPressed();
        }
    
  • Fragments that have an interest in the back button will implement this interface

    public class MyFragment extends Fragment implements MyActivity.HandlesOnBackPressed {
    
        ...
    
        @Override
        public boolean onBackPressed() {
    
            ...
    
  • When you do the fragment transaction:

    1. Give the HandlesOnBackPressed fragment a unique tag when you do the transaction (replace etc.)
    2. When you push the transaction to the back stack, give that back stack entry the same tag.

          MyFragment fragment = MyFragment.newInstance(...
          fragmentManager
                .beginTransaction()
                .replace(R.id.fragment_container, fragment, "MyFragment")
                .addToBackStack("MyFragment")
                .commit();
      

    The fact that I used the class name has no bearing on the logic. The only requirement is that the fragment tag and the back stack entry tag be the same.

  • And here is the secret sauce. Override onBackPressed in the activity:

        @Override
        public void onBackPressed() {
    
            FragmentManager fragmentManager = getSupportFragmentManager();
            int count = fragmentManager.getBackStackEntryCount();
            if (count > 0) {
    
                FragmentManager.BackStackEntry topBackStackEntry = fragmentManager.getBackStackEntryAt(count - 1);
                if (topBackStackEntry != null) {
    
                    String tag = topBackStackEntry.getName();
                    if (tag != null) {
    
                        // since super.onBackPressed() hasn't been called yet,
                        // the top back stack entry should match with the current fragment
                        Fragment fragment = fragmentManager.findFragmentByTag(tag);
                        if (fragment instanceof HandlesOnBackPressed) {
    
                            if (((HandlesOnBackPressed) fragment).onBackPressed()) {
    
                                // the fragment handled the back press, 
                                // so don't call super.onBackPressed()
                                return; 
                            }
                        }
                    }
                }
            }
    
            DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
            if (drawerLayout != null && drawerLayout.isDrawerOpen(GravityCompat.START)) {
                drawerLayout.closeDrawer(GravityCompat.START);
            } else {
                super.onBackPressed();   // pops back stack, onBackStackChanged() is called
            }
    
        }
    

Google, why do you make me do this stuff?