I'm new to Android development and developing an application using Android's default Navigation drawer layout.
I'm using fragment in the application.
I want to get back to previous fragment when back button is pressed on next fragment.
The onBackPress must implement following functions
Get back to previous fragment when on next fragment
Close drawer when navigation drawer is open
Exit app on double back press when in fragment1
This is what my code is in MainActivity
while creating new fragment
// replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.commit();
}
onBackPress
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (getFragmentManager().getBackStackEntryCount() > 0) {
FragmentManager fm = getSupportFragmentManager();
fm.popBackStack();
} else {
super.onBackPressed();
}
}
But this is not working and on pressing back exits the application except when Navigation drawer is open it is closed.
You are not adding the fragment to the backstack. You just have to do
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
.replace(R.id.content_frame, fragment);
.addToBackStack(null);
.commit();
And since the Backstack is actually handled by the back button, you do not need to handle this scenario in onBackPressed(), so you can change it to just:
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
You have to add the Fragment in your FragmentTransaction to the backstack.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment).addtoBackStack(null).commit();
By giving the tag null they all get grouped by that tag. So if you need to close them all together you can do so or navigate to a certain one.
I also would not use replace(), because that one is incredibly buggy with the backstack.
Try to use remove() and then add().
You should add your fragment to the back stack and modify your code this way:
// this variable is needed to know how many times the back key has been pressed.
// It is incremented and reset accordingly to the logic you described
int mBackPressCount = 0;
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
if (getFragmentManager().getBackStackEntryCount() == 0) {
// if there are no fragments in your back stack check the mBackPressCount
if (mBackPressCount++ > 0) {
// if you pressed back for the second time this line will terminate the activity
super.onBackPressed();
}
} else {
// this line will pop the fragment from the back stack,
// no need to pop it manually
super.onBackPressed();
}
}
}
Add the fragment to the back stack:
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.commit();
// when you add a fragment you should reset the back press count
mBackPressCount = 0;
}
Reset mBackPressCount when open and close the drawer. If you have pressed the back key once and you open the drawer the counter has to be set to 0 again.
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
}
#Override
public void onDrawerOpened(View drawerView) {
mBackPressCount = 0;
}
#Override
public void onDrawerClosed(View drawerView) {
mBackPressCount = 0;
}
#Override
public void onDrawerStateChanged(int newState) {
}
});
Related
I am developing an android app using fragments. I have five fragments. Those are A,B,C,D,E . My first fragment A is the main fragment. First I traverse from A to B then from B to C. In C when I press back button I want it to go back to A. I have used the below code for calling B fragment from A. This same method is used for calling another fragments.
FragmentB fragment = new FragmentB();
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction().addToBackStack("tag");
transaction.replace(R.id.content_frame, fragment);
transaction.commit();
The back button code in the activity is as following
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
How to solve this issue please help me.
You can try this:
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} FragmentManager fragmentManager = getSupportFragmentManager();
int backCount = fragmentManager.getBackStackEntryCount();
System.out.println("back count " + backCount);
if(backCount==0)
{
actionBar.setTitle("Home");
//Here you can show alert dialog for exit the app?
}
/* else if(backCount==1)
{
}*/
else if(backCount==1)
{
fragmentManager.popBackStack();
// setTitle("Home");
navigationView.getMenu().getItem(0).setChecked(true);
actionBar.setTitle("Home");
}
else if(backCount>1)
{
for(int i=fragmentManager.getBackStackEntryCount();i>=1;i--)
{
fragmentManager.popBackStack();
System.out.println("back count loop" + fragmentManager.getBackStackEntryCount());
}
actionBar.setTitle("Home");
}
}
Try this:
#Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawers();
return;
}
// This code loads home fragment when back key is pressed
// when user is in other fragment than home
if (shouldLoadHomeFragOnBackPress) {
// checking if user is on other navigation menu
// rather than home
if (navItemIndex != 0) {
navItemIndex = 0;
CURRENT_TAG = TAG_HOME;
loadHomeFragment();
return;
}
}
super.onBackPressed();
}
Refer this reference : https://www.androidhive.info/2013/11/android-sliding-menu-using-navigation-drawer/
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();
}
}
}
Hi I have created fragments in app drawer and now when I am pressing the back button on a fragment, it is closing the application.
There is already one existing onKeyDown in the webView of Main activity.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (myWebView.canGoBack()) {
myWebView.goBack();
} else {
finish();
}
return true;
}
}
return super.onKeyDown(keyCode, event);
For the onBackPressed method
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
Fragment Impementation method,
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_main, fragment);
ft.addToBackStack("close");
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
When you add a fragment to some container or inflate it using xml, it is not added to the backstack and so, when 'onBackPressed' occurs it throws the last activity from the backstack- which is the activity hosting the fragment and thus exiting the application.
I think this post:
Android: Fragments backStack
can help you, it explains how to add the fragment transaction to the backstack:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(..............);
fragmentTransaction.addToBackStack("fragment transaction name, not required");
fragmentTransaction.commit();
You need to do this in following way
#Override
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();
}
}
}
I think you dont add the fragments to the backstack.
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
//your code
fragmentTransaction.addToBackStack("your_tag");
When you evoke a fragment add it to stack like this
fragmentTransaction.addToBackStack("fragment");
and then in onBackPress pop it from stack like this
FragmentManager fm = getActivity()
.getSupportFragmentManager();
fm.popBackStack ("fragment", FragmentManager.POP_BACK_STACK_INCLUSIVE);
Fragment Overlap
I have 5 fragments.On pressing back button I want to move to home fragment no matter how many fragments are opened.
If I move from
[1] --> [2] and Press back [1] shown home fragment
[1] --> [3] and Press back [1] shown home fragment
[1] --> [4] and Press back [1] shown home fragment
[1] --> [5] and Press back [1] shown home fragment
As I want No Problem.
But Problem is
[1] --> [2] --> [3] and Press back home fragment overlap on [3]
[1] --> [2] --> [4] and Press back home fragment overlap on [4]
[1] --> [2] --> [5] and Press back home fragment overlap on [5]
I have added only home fragment to backStack and used replace fragment method.
Why this is happening???
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.all_activity_layout);
setToolbar();
addFragment(AttractionsFragment.newInstance());
setNavigationDrawer();
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_attractions:
if (mCurrentNavigationDrawerItem != 0) {
mCurrentNavigationDrawerItem = 0;
replaceFragment(AttractionsFragment.newInstance());
}
break;
case R.id.nav_packages:
if (mCurrentNavigationDrawerItem != 1) {
mCurrentNavigationDrawerItem = 1;
replaceFragment(PackagesFragment.newInstance());
}
break;
case R.id.nav_passes:
if (mCurrentNavigationDrawerItem != 2) {
mCurrentNavigationDrawerItem = 2;
replaceFragment(PassesFragment.newInstance());
}
break;
case R.id.nav_coupons:
if (mCurrentNavigationDrawerItem != 3) {
mCurrentNavigationDrawerItem = 3;
replaceFragment(CouponsFragment.newInstance());
}
break;
case R.id.nav_more:
if (mCurrentNavigationDrawerItem != 4) {
mCurrentNavigationDrawerItem = 4;
replaceFragment(MoreFragment.newInstance());
}
break;
}
mNavigationView.getMenu().getItem(mCurrentNavigationDrawerItem).setChecked(true);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
public void replaceFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Get Current Visible fragment
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
// Add to back stack only if it is AttractionsFragment
if (f instanceof AttractionsFragment) {
transaction.addToBackStack(fragment.getClass().getName());
}
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
Log.d("Navigation", "BackStack Count:" + getSupportFragmentManager().getBackStackEntryCount());
}
public void addFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.fragment_container, fragment, "AttractionsFragment");
transaction.commit();
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
You need to pop the 2nd fragment before navigating to 3rd fragment.
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
// Add to back stack only if it is AttractionsFragment
if (f instanceof AttractionsFragment) {
transaction.addToBackStack(fragment.getClass().getName());
} else {
activity.getSupportFragmentManager().popBackStackImmediate();
}
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
Replace your container view with first fragment:
#Override
public void onBackPressed() {
FragmentManager fm = getFragmentManager();
fm.beginTransaction().replace(R.id.fragment_container, new **your_first_fragment**()).commit();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
Remove the transaction.addToBackStack(fragment.getClass().getName()); line it will work fine. Please check the code below
public void replaceFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Get Current Visible fragment
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
// Add to back stack only if it is AttractionsFragment
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
Log.d("Navigation", "BackStack Count:" + getSupportFragmentManager().getBackStackEntryCount());
}
In OnBackpress add this code:
#Override
public void onBackPressed() {
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
if (getFragmentManager().findFragmentById(R.id.activity_container) instanceof HomeFragment) {
super.onBackPressed();
} else {
replaceFragment(this, new HomeFragment());
}
}
And change your replaceFragment and AddFragment methods in all cases with the code given below:
public void addFragment(final Activity mActivity, final Fragment newFragment, final Fragment hideFragment) {
final FragmentManager fragmentManager = mActivity.getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.hide(hideFragment);
fragmentTransaction.add(R.id.activity_container, newFragment, newFragment.getClass().getSimpleName());
fragmentTransaction.addToBackStack(hideFragment.getClass().getSimpleName());
fragmentTransaction.commitAllowingStateLoss();
}
public void replaceFragment(final Activity mActivity, final Fragment newFragment) {
final FragmentManager fragmentManager = mActivity.getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.activity_container, newFragment, newFragment.getClass().getSimpleName());
fragmentTransaction.commit();
}
Where activity_container is the FrameLayout Id in xml file of the activity.
In onCreate of your activity call replaceFragment method instead of addFragment. And in all navigation item click event, call replaceFragment method.
If you are adding/launching all three fragments in the same activity, instead of the add() method of FragmentTransaction for showing Fragment3, use the replace() method of FragmentTransaction (replace Fragment2 with Fragment3). The replace method removes the current fragment from backstack before adding the new fragment. If you are launching Fragment3 from a different activity, and thus you can't/don't want to use replace(), remove Fragment2 from backstack before starting the new activity (which adds fragment3):
// in Fragment2, before adding Fragment3:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.remove(this) // "this" refers to current instance of Fragment2
.commit();
fragmentManager.popBackStack();
// now go ahead and launch (add) fragment3
// if fragment3 is launched from a different activity,
// start that activity instead
fragmentManager.beginTransaction()
.add(R.id.a_container_view_in_activity, new Fragment3(),
Fargment3.FRAGMENT3_ID)
.commit();
This will solve your problem. Try this..
try this:
in your onBackPressed:
#Override
public void onBackPressed(){
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack();
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed();
}
}
also in your replace fragment- to solve overlapping issue try
transaction.replace(((ViewGroup)(getView().getParent())).getId(), fragment);
or
getSupportFragmentManager().beginTransaction().replace(R.id.container,new FirstFragment()).commit();
Try changing your code in replace fragment:
public void replaceFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Get Current Visible fragment
//Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
AttractionsFragment myFragment = (AttractionsFragment)getFragmentManager().findFragmentByTag("MY_FRAGMENT");
if (myFragment != null && myFragment.isVisible()) {
// Add to back stack only if it is AttractionsFragment
transaction.addToBackStack(null);
}
transaction.replace(R.id.fragment_container, fragment, "MY_FRAGMENT");
transaction.commit();
Log.d("Navigation", "BackStack Count:" + getSupportFragmentManager().getBackStackEntryCount());
}
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.