How to handle onBackPressed() in multiple fragment - android

I am Android beginner, I am developing an app in which I have used multiple fragments through an activity.
private void displaySelectedScreen(int itemId) {
Fragment fragment = null;
switch (itemId) {
case R.id.nav_home:
fragment = new HomeFragment();
break;
case R.id.nav_attendance:
fragment = new AttendanceFragment();
break;
case R.id.nav_notification:
fragment = new NotificationFragment();
break;
case R.id.nav_event:
fragment = new EventFragment();
break;
case R.id.nav_fee:
fragment = new FeesFragment();
break;
case R.id.nav_news:
fragment = new NewsFragment();
break;
}
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.frame_container, fragment);
ft.addToBackStack(null);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
and use an onBackPressed() method to close an app if the drawer is already close. Now I want to close an app if current fragment is HomeFragment and if current fragment is not HomeFragment then replace by HomeFragment. I don't know, how it does?
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout)findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
closeApp();
}
}

You can add tag to your fragment. in this way you will only have to check the tag name.
Fragment fragment = new Fragment();
getFragmentManager().beginTransaction()
.replace(R.id.FrameLayoutId,fragment,"TAG_NAME")
.addToBackStack("SOURCE_TAG_NAME").commit();
This is how to check your fragment tag, put this checking on your backpress method on the activity or in your closeApp() method
function void closeApp(){
Fragment fragment = getFragmentManager().findFragmentByTag("HomeActivity");
if (fragment != null) {
if(fragment.isVisible()){
HomeActivity.this.finish();
}
}
}

Use this code onBackPressed() method in NavigationActivity. I hope that can solve you.
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
Fragment f = getVisibleFragment();// to get which fragment now
if (f.getClass() != MainFragment.class) {
Fragment fragment = null;
try {
fragment = (Fragment) MainFragment.class.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame, fragment).commit(); // this is your framelayout
}else {
super.onBackPressed();
}
}
}
getVisibleFragment() function
public Fragment getVisibleFragment() {
FragmentManager fragmentManager = NavigationActivity.this.getSupportFragmentManager();
List<Fragment> fragments = fragmentManager.getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (fragment != null && fragment.isVisible())
return fragment;
}
}
return null;
}

For simple, just go to your HomeFragment.java and edit the method onBackPressed() to exit the application using finish().
And for others Fragment.java, just use popBackStack() function, you can search for it here :
https://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()

In your MainActivity class override onBackPressed and display dialogbox there like this:
#Override
public void onBackPressed() {
//show dialog box here
}
In each Fragment implement onResume() method with following code:
#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){
//homefragment class name
Class fragmentClass = HomeFragment.class;
try {
Fragment fragment = (Fragment) fragmentClass.newInstance();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
return false;
}
});
}

Related

Adding back button to fragment

I have a bottom navigation bar that contains 4 fragments and when a tab is selected a new instance of that fragment is loaded.
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = HomeFragment.newInstance();
break;
case R.id.navigation_cards:
fragment = CardsFragment.newInstance();
break;
case R.id.navigation_deals:
fragment = DealsFragment.newInstance();
break;
case R.id.navigation_settings:
fragment = SettingsFragment.newInstance();
break;
}
if (fragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content, fragment);
fragmentTransaction.commit();
}
return true;
}
};
Now in my HomeFragment there is a RecyclerView that On Item Select it opens a new Fragment:
myViewHolder.cardView.setOnClickListener(view -> {
System.out.println("clicked");
Fragment fragment = new TargetDetailsFragment();
FragmentTransaction ft = ((AppCompatActivity) context).getSupportFragmentManager()
.beginTransaction();
ft.replace(R.id.content, fragment).addToBackStack(null);
ft.commit();
});
I want to add a back button to the TargetDetails Fragments that takes you back to the home page when selected and I attempted doing that by implementing OnBackStackChangedListener in the Main activity
#Override
public void onBackStackChanged() {
shouldDisplayHomeUp();
}
public void shouldDisplayHomeUp(){
//Enable Up button only if there are entries in the back stack
boolean canback = getSupportFragmentManager().getBackStackEntryCount()>0;
getSupportActionBar().setDisplayHomeAsUpEnabled(canback);
}
#Override
public boolean onSupportNavigateUp() {
//This method is called when the up button is pressed. Just the pop back stack.
getSupportFragmentManager().popBackStack();
return true;
}
}
but the problem is when I click on it its reloads the HomeFragment Again but I simply want it to go back to the saved instance of that Fragment
Here is my code that I have used for the ViewPager, the idea is to see if the current page number is 0 than to proceed super.onBackPressed(); otherwise go to the previous fragment:
#Override
public void onBackPressed() {
if(vpPager.getCurrentItem()!=0) {
vpPager.setCurrentItem(vpPager.getCurrentItem()-1, true);
} else {
super.onBackPressed();
}
}
By adding below code in your Activity.
The fragment back stack can be managed.
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getFragmentManager().popBackStack();
}
}
Hello #Bolu Okunaiya i think you should try this it will help you to manage backstack to desired fragment without loading same fragment again.
For Stop loading previous fragment you should use "add" instead of "replace" with your FragmentTransaction
Inside your MainActivity
#Override
public void onBackStackChanged() {
//shouldDisplayHomeUp();
Fragment currentFragment = getActivity().getFragmentManager()
.findFragmentById(R.id.fragment_container);
if (currentFragment instanceof TargetDetails) {
Log.v(TAG, "your current fragment is TargetDetails");
popBackStackImmediate(); //<<<< immediate parent fragment will open,which is your HomeFragement
}
}
To use popBackStackImmediate() you need to *replace FragmentA with FragmentB and use addToBackstack() before commit().

addToBackStack Not working

I am trying to close the fragment and wants to resume the main activity by using the addToBackStack in my fragment implimentation but it is not working. Back button is closing the application.
The fragment implimentation method that I am using is,
private void dispaySelectedScreen(int id) {
Fragment fragment = null;
switch (id) {
case R.id.facebook_login:
fragment = new FacebookLogin();
break;
case R.id.memes:
fragment = new Memes();
break;
case R.id.submit_image:
fragment = new SubmitImage();
break;
case R.id.discussion:
fragment = new Discussions();
break;
case R.id.invite:
fragment = new Invite();
break;
case R.id.connect_fb:
fragment = new FacebookConnect();
break;
case R.id.connect_twitter:
fragment = new TwitterConnect();
break;
case R.id.connect_instagram:
fragment = new InstaConnect();
break;
}
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_main, fragment);
ft.addToBackStack(null);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
I have also declared one onBackPressed method for the drawer,
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
Please suggest..
fragment.addToBackStack(null) is enough to open the previous activity but if you want to handle some action on back pressed apart from removing the fragment then we override onBackPressed(), so this is my tested approach, kindly have a look:-
Below is my implementation:-
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_holder, new MyFragment(), "MY_FRAG")
.addToBackStack(null).commit();
}
#Override
public void onBackPressed() {
MyFragment fragment = (MyFragment) getSupportFragmentManager().findFragmentByTag("MY_FRAG");
if (fragment != null) {
if (fragment.isVisible()) {
//todo perform any action if you want when fragment is removed
}
} else {
super.onBackPressed();
}
}
I see you are using replace on transaction in that way your fragment will pop up from stack but it will reload i.e onCreateView() of that fragment will be called . Just replace
ft.replace(R.id.content_main, fragment);
to
ft.add(R.id.content_main, fragment);
For handling back button use following code .
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
//that means your stack is empty and you want to close activity
finish();
} else {
// pop the backstack here
getSupportFragmentManager().popBackStackImmediate();
}
}
}

onBack pressed in activity and fragment

Navigation drawer with fragments. I have placed one fragment on main activity. But if i back press the same fragment comes again. How can I handle this??
and secondly how to implement onBackpressed in fragments??
Can anybody help me out?
in onCreate of main activity I have
FragmentTransaction tx = getFragmentManager().beginTransaction();
tx.replace(R.id.mainFrame, new PlaceOrderFragment());
tx.commit();
and in back press of it I have
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
First you need to add the fragmnet to back stack so we could retrieve it later in onBackPressed()
Replace your fragmnet transaction with this
FragmentTransaction tx = getFragmentManager().beginTransaction();
tx.replace(R.id.mainFrame, new PlaceOrderFragment());
// HERE WE WILL ADD FRAGMENT TO BACKSTACK SO WE COULD GET BACK TO IT
tx.addToBackStack(null);
tx.commit();
Replace your onBackPressed with this
#Override
public void onBackPressed() {
// CHECKS HOW MANY FRAGMENTS ARE IN THE BACKSTACK
int count = getFragmentManager().getBackStackEntryCount();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
if (count == 0) {
// IF NO FRAGMENT IN THE BACKSTACK CALL
super.onBackPressed();
} else {
// GET THE LAST OPENED FRAGMENT
getFragmentManager().popBackStack();
}
}
}
You can do this using Interface. That interface will implemented in each fragment. Here is a simple example:
public interface OnBackPressedListener {
void onBackPressed();
}
Here, if you implement this interface in your fragment then you will found this method:
#Override
public void onBackPressed() {
getActivity().finish(); // Or Do your specific task
}
Now your Activity that holds that fragment , that should use onBackPressed() callback. Write bellow code in that method
#Override
public void onBackPressed() {
if (YOUR_DRAWER.isDrawerOpen(GravityCompat.START)) {
YOUR_DRAWER.closeDrawer(Gravity.LEFT); //CLOSE Nav Drawer!
return;
}
Fragment fragment=getYourVisibleFragment();
if(fragment!=null){
((OnBackPressedListener)fragment).onBackPressed();
}else{
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
If you want to get Visible fragment then just use this method
public <F extends Fragment> F getVisibleFragment() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (fragment != null && fragment.isVisible()) {
return (F) fragment;
}
}
}
return null;
}
That's it :)
FragmentTransaction tx = getFragmentManager().beginTransaction();
tx.replace(R.id.mainFrame, new PlaceOrderFragment()).addToBackStack("your tag");
tx.commit();
Override onBackPress() and try following code.
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//your other utility code if needed
} else {
getFragmentManager().popBackStack();
}
}
Hope this will work for you.
Replace ypu fragment in onCreate with fragment id , and then implement onBackpressed on the same activity and find that fragment with id and check is it visible or null and then perform operations based on it.
hope you got this.

Getting Empty fragment after popbackstack

When I am pressing back button getting the fragment as empty. Not getting the previous fragment poped back. Tried many solutions but didn't work. What is the solution for this ? I have no idea how to solve this.
private void displayView(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = mHomeFragmentInstance;
break;
case 1:
fragment = mOrderFragmentInstance;
break;
case 2:
fragment = mOrdersheetFragmentInstance;
break;
case 3:
fragment = mMyorderwidgetFragmentInstance;
break;
case 4:
Intent intent=new Intent(this,LoginActivity.class);
startActivity(intent);
clearValues();
finish();
return;
default:
fragment = mHomeFragmentInstance;
break;
}
if (fragment != null) {
replaceFragment(fragment, position);
}
}
/**
* When using the ActionBarDrawerToggle, you must call it during
* onPostCreate() and onConfigurationChanged()...
*/
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
public void replaceFragment(Fragment fragment){
if (fragment != null) {
Fragment currentFragment = this.getSupportFragmentManager().findFragmentById(R.id.frame_container);
if(null != currentFragment ){
if(currentFragment.equals(fragment)){
return;
}else{
getSupportFragmentManager().beginTransaction().remove(currentFragment).commit();
}
}
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.frame_container, fragment);
ft.addToBackStack(null);
ft.commit();
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
public void replaceFragment(Fragment fragment, int position){
adapter.selectItem(position);
Log.i("TAG", "replaceFragment:"+fragment.getClass().getName()+":"+position);
replaceFragment(fragment);
Log.i("TAG", "Add"+fragment.getClass().getName()+"backStackFragment");
if(fragment.equals(mHomeFragmentInstance)){
Log.i("TAG", "clear backStackFragment");
backStackFragment.clear();
backStackFragment.add(mHomeFragmentInstance);
}
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(drawerContainer);
}
#Override
public void setTitle(CharSequence title) {
mTitle = title;
//getActionBar().setTitle(Html.fromHtml("<font color='#983A1B'>" + title + "</font>"));
View view = getActionBar().getCustomView();
//((TextView)view.findViewById(R.id.title)).setText(Html.fromHtml("<font color='#983A1B'>" + title + "</font>"));
((TextView)view.findViewById(R.id.title)).setText(Html.fromHtml("<font color='"+ ApplicationInfo.getPlfColor(this)+"'>" + title + "</font>"));
}
#Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
if(fm.getBackStackEntryCount() > 1) {
fm.popBackStack();
}else {
//super.onBackPressed();
finish();
}
}
}
Just add addToBackStack while you are transitioning between your fragments like below:
fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();
if you write addToBackStack(null) , it will handle it by itself but if you give a tag , you should handle it manually.

onBackPressed closing app in fragments using NavigationDrawer

I'm using NavigationDrawer with some fragments, the problem is when I'm in a fragment and hit the back button, it makes the app close, then I have to open it again, put my username and password all over again to use the app, how can I prevent that from happen?
public class NavigationMain extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
}
public void setFragmentList(int posicao) {
Fragment fragment = null;
switch (posicao) {
case 0:
fragment = new MainFragment();
break;
case 1:
fragment = new MensagensFragment();
break;
case 2:
fragment = new EscolasFragment();
break;
case 3:
fragment = new AutorizadasFragment();
break;
case 4:
fragment = new CadastroFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
// update selected item and title, then close the drawer
navigationAdapter.resetarCheck();
navigationAdapter.setChecked(posicao, true);
layoutDrawer.closeDrawer(linearDrawer);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
}
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getFragmentManager().popBackStack();
}
}
I think you missed to add the fragment transaction in your back stack. Try the following:
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).addToBackStack(null).commit();

Categories

Resources