Search code examples
javaandroidandroid-fragmentsonbackpressed

Back Button Implementation in Fragment ViewPager


I have 3 Fragments inside a ViewPager. I have different back button functionalities which I want to implement for each Fragment. At the moment, I have created methods in each fragment which correspond to what I want the back button to do. I implemented an interface in my activity with the following methiod:

@Override
public void onCameraBack(int i) {
    currFrag = i;
}

The idea here is that there are three fragments, each fragment calls this method in its onStart() method. Fragment 0 passes 0, fragment 1 passes 1 and fragment 2 passes 2. So in this way the holding activity knows which fragment is visible. Now I am trying to get a reference to that fragment to be able to call the backbutton method I have implemented in it. I tried using this :

@Override
public void onBackPressed() {
    if (currFrag == 0) {

    }
    else if (currFrag == 1) {
        FragmentBTesting fragmentBTesting= new FragmentBTesting();
        fragmentBTesting.FragmentBBack();
    }
}`

but this doesn't work. I can't use the findFragmentbyId method since my fragments do not have fragment tags in their XML, they fill the whole screen and their views are defined using linearLayouts. My question is how can I get an instance of the fragment so I can call its FragmentBack() method.

Here is my full activity

  public class FragmentActivityTesting extends FragmentActivity implements FragmentATesting.logoutListener,FragmentBTesting.onCameraBack {
ViewPager viewPager = null;
SessionManager session = new SessionManager(MyApp.getContext());
int currFrag;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_fragment_activity_testing);
    viewPager = (ViewPager) findViewById(R.id.pic_pager);
    setStatusBarColor();
    FragmentManager fragmentManager = getSupportFragmentManager();
    viewPager.setAdapter(new MyAdapter(fragmentManager));
    viewPager.setCurrentItem(1);
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("CLOSE_ALL");
    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            finish();
        }
    };
    registerReceiver(broadcastReceiver, intentFilter);

}
@TargetApi(21)
public void setStatusBarColor() {
    Window window = this.getWindow();
    // clear FLAG_TRANSLUCENT_STATUS flag:
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

    // add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

    if (Integer.valueOf(android.os.Build.VERSION.SDK) >= 21) {
        window.setStatusBarColor(this.getResources().getColor(R.color.green));

    }

}

@Override
public void logout() {
    session.logOut();
    Intent a = new Intent(this,MainActivity.class);
    startActivity(a);
    Intent intent = new Intent("CLOSE_ALL");
    this.sendBroadcast(intent);
    finish();
}
@Override
public void onBackPressed() {
    if (currFrag == 0) {

    }
    else if (currFrag == 1) {
        FragmentBTesting fragmentBTesting= new FragmentBTesting();
        fragmentBTesting.FragmentBBack();
    }
}


@Override
public void onCameraBack(int i) {
    currFrag = i;
}
}

class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
    super(fm);
}

@Override
public Fragment getItem(int position) {
    Fragment fragment = null;
    if (position ==0) {
        fragment = new FragmentATesting();
    }
    else if (position == 1) {
        fragment = new FragmentBTesting();
    }
    else if (position == 2) {
        fragment = new FragmentCTesting();
    }
    return fragment;
}

@Override
public int getCount() {
    return 3;
}

}

Solution

  • Instead of telling your activity what fragment you are currently on, why not tell it what to execute when back is pressed?

    In your activity you can have a field to hold the callback field (as a Runnable, I know so much hate. You can make your own interface if you want), the setter, and then the onBackPressed implementation. Here is a snippet from my code that works. Im using Guava's Optional class, but you can null it instead if you're into that kinda thing.

    This is the Activity which should implement ActivityWithHomeButton

    private Optional<? extends Runnable> backButtonListener = Optional.absent();
    
    @Override
    public void onBackPressed() {
        // Check if there is a custom back button
        if (backButtonListener.isPresent()) {
            backButtonListener.get().run();
            backButtonListener = Optional.absent();
        } else {
            super.onBackPressed();
        }
    }
    
    @Override
    public void setBackButtonListener(Optional<? extends Runnable> backButtonListener) {
        this.backButtonListener = backButtonListener;
    }
    

    Here is the interface I implement in the activity

    public interface ActivityWithHomeButton {
        void setBackButtonListener(Optional<? extends Runnable> runnable);
    }
    

    and of course the usage from a fragment

    parent.setBackButtonListener(Optional.of(new Runnable() {
            @Override
            public void run() {
                // do back button stuff
            }
        }));
    

    You can put this wherever you want in the fragment. You are also going to want to clear the back button listener whenever you no longer need it (onPause). You can do this as such

    parent.setBackButtonListener(Optional.<Runnable>absent());
    

    Where parent can be attained using the standard activity-fragment communication pattern detailed here (http://developer.android.com/training/basics/fragments/communicating.html). This code goes in your fragment

    private ActivityWithHomeButton parent;
    
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            parent = (ActivityWithHomeButton) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement ActivityWithHomeButton");
        }
    }
    

    Hope it helps!