Fragment addToBackStack closing App - android

I didnt find any solution for my problem.
I got several Fragments (dynamically created), but my Back Button is not working at all,
pressing it will close the App, whatever fragment is "active".
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.itemAdd:
FragmentTransaction tx = getFragmentManager().beginTransaction();
Fragment fragment = new NeuesProduktFrag();
tx.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right,
R.anim.slide_in_left, R.anim.slide_out_right);
tx.replace(R.id.main, fragment);
tx.addToBackStack(null);
tx.commit();
return true;
Everything works fine, but after entering "NeuesProduktFrag" Fragment and pressing Back-Button my App closes. Tried it in different Buttons etc.
Overriding onBackPressed is not needed right ?
addToBackStack should do the trick or not ?

After i struggeled a long time, this is my final Code:
#Override
public void onBackPressed() {
// initialize variables
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
// check to see if stack is empty
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
ft.commit();
}
else {
if (this.lastBackPressTime < System.currentTimeMillis() - 4000) {
Toast.makeText(this, "Nochmal drücken zum Beenden!", 4000).show();
this.lastBackPressTime = System.currentTimeMillis();
} else{
super.onBackPressed();
}
}
}
I used it in my FragmentActivity and added a double tab to close the App finally.

I guess the problem occurs when using getFragmentManager() instead of support library's getSupportFragmentManager() in support library's FragmentActivity. For example, when you want PreferenceFragment and setSupportActionBar() together.
I've solved the problem in my ActionBarActivity by copy-pasting onBackPressed() implementation from android.app.Activity with some changes:
#Override
public void onBackPressed() {
if (getFragmentManager().popBackStackImmediate()) return;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
finish();
else
finishAfterTransition();
}

My code worked changing from FragmentActivity to Activity.
edit: typing error

Press Back Button to exit the application
#Override
public void onBackPressed() {
// initialize variables
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
// check to see if stack is empty
if (fm.getBackStackEntryCount() > 1) {
fm.popBackStack();
ft.commit();
} else {
if (backPressedTime + 2000 > System.currentTimeMillis()) {
backToast.cancel();
finishAffinity();
System.exit(1);
return;
} else {
backToast = Toast.makeText(getBaseContext(), "press back again to exit", Toast.LENGTH_LONG);
backToast.show();
}
backPressedTime = System.currentTimeMillis();
}
}

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 with onBackPressed method

I have created a tabbed activity inside a navigation drawer activity. I have linked the lists inside the navigation drawer with individual fragments. I also used the command ft.addToBackStack(null) before ft.commit(). It was perfectly fine and I was able to use it to close the fragments inside the navigation drawer. now I have created webviews inside the fragments of the tabbed activity (home page). I added the onBackPressed to go back inside the webview and now the addToBackStack method stopped working.
For the navigation drawer fragments,
private void dispaySelectedScreen(int id) {
Fragment fragment = null;
switch (id) {
case R.id.fragment1:
fragment = new Fragment1();
break;
case R.id.fragment2:
fragment = new Fragment2();
break;
case R.id.fragment3:
fragment = new Fragment3();
break;
case R.id.fragment4:
fragment = new fragment4();
break;
}
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_main, fragment);
ft.addToBackStack(null);
ft.commit();
}
onBackPressed Method
#Override
public void onBackPressed() {
if (hWebView.canGoBack()) {
hWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate())
if (sWebView.canGoBack()) {
sWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate())
if (dWebView.canGoBack()) {
dWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate());
}
Please help me out!!!
try this code: override onBackPressed() in your tabbed activity (home page).
#Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
if (hWebView.canGoBack()) {
hWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate())
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
} else {
super.onBackPressed();
}
}

Single Instance fragment back stack managerment

I am working on single activity based principle. But I am facing a problem when the same fragment is open again because its again adds in fragment backstack entry. So backstack contains multiple backstack entries for same fragment. This creates problem on back navigation.
Example :- A|B|C|D|A|C|A
So when I press back key same fragment is displaying multiple times. Is there any way to reuse the existing fragment from backstack entry.
I am managing my backstack like this :-
fragmentManager.beginTransaction().setCustomAnimations(R.anim.fragment_enter,
R.anim.fragment_exit, R.anim.pop_enter, R.anim.pop_exit).
add(R.id.frameLayout, fragment).addToBackStack(backStateName).commit();
Any kind of help will be appreciated.
private void createOrResumeFragment(String fragmentTag){
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
boolean fragmentPopped = manager.popBackStackImmediate (fragmentTag, 0);
Fragment fragment = manager.findFragmentByTag(fragmentTag);
if(!fragmentPopped && fragment == null){
//Create an new instance if it is null and add it to stack
fragment = new MyFragment();
ft.addToBackStack(fragmentTag);
}
ft.replace(R.id.framelayout, fragment);
ft.commit();
}
Trying this using the fragment list
See the Answer Here
Initialize the fragments list
static List<String> fragments = new ArrayList<String>();
on Start of first fragment on Activity add this
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.frame, new AFragment()).commit();
fragments.add("package.fragment.AFragment");
}
Code to fragment change and take in back stack
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
//fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
if(!fragments.contains(backStateName)) {
// ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
// ft.setCustomAnimations(R.anim.fade_in, R.anim.fade_out);
ft.replace(R.id.frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
fragments.add(backStateName);
System.out.println("backStateName" + fragments);
}
else
{
ft.replace(R.id.frame, fragment);
ft.commit();
}
onBackpressed
#Override
public void onBackPressed() {
if(fragments.size()>0)
{
fragments.remove(fragments.size()-1);
}
super.onBackPressed();
}
for back remove stack
final android.app.FragmentManager fm = getFragmentManager();
fm.addOnBackStackChangedListener(new android.app.FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (getSupportFragmentManager().getBackStackEntryCount() ==0) {
// dLayout.closeDrawers();
finish();
}
else
{
// dLayout.closeDrawers();
}
}
});
Before adding or replacing the fragment on backstack, check that if the fragment already in backstack or not.
boolean fragmentPopped = fragmentManager.popBackStackImmediate(backStateName, 0);
if (fragmentPopped) {
// fragment is popped from backStack
} else {
// add or replace your fragment here
}
public void changeFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment currentVisibleFragment = fragmentManager.findFragmentById(R.id.container);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container, fragment, fragment.getClass().getSimpleName());
if (!currentVisibleFragment.getClass().getSimpleName().trim().equalsIgnoreCase(fragment.getClass().getSimpleName().trim())) {
for (int i = fragmentManager.getBackStackEntryCount() - 1; i > 0; i--) {
if (fragmentManager.getBackStackEntryAt(i).getName().equalsIgnoreCase(fragment.getClass().getSimpleName())) {
fragmentManager.popBackStack(fragmentManager.getBackStackEntryAt(i).getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
fragmentTransaction.addToBackStack(fragment.getClass().getSimpleName());
} else {
fragmentManager.popBackStack();
fragmentTransaction.addToBackStack(fragment.getClass().getSimpleName());
}
fragmentTransaction.commit();
}
boolean doubleBackToExitPressedOnce = false;
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
super.onBackPressed();
} else {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
finish();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Are you sure you want to exit?", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce = false;
}
}, 2000);
}
}
Call the method to replace fragment with single entry in backstack
changeFragment(new YourFragmentClassName());

Doesn't change fragment backstack size when I press back button in Actvity

This is my code:
FragmentManager fragmentManager = getSupportFragmentManager();
try {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commitAllowingStateLoss();
} catch (Exception e) {
e.printStackTrace();
}
When I am adding first fragment, my method getSupportFragmentManager().getBackStackEntryCount() returns 0.
When I am adding second fragment getBackStackEntryCount() returns 1, but when I am pressing back button getBackStackEntryCount() still returns 1.
Why?
UPD -
#Override
public void onBackPressed() {
super.onBackPressed();
updateToolbar(); // here I check backstackCount and update Toolbar
}
UPD2 -
private void updateToolbar() {
if (getSupportFragmentManager().getBackStackEntryCount()() > 0) {
showBackButtonOnToolBar();
} else {
showProfileButtonOnToolBar();
}
}
You will have to call popBackStack() from your onBackPressed():
#Override
public void onBackPressed()
{
if (getSupportFragmentManager().getBackStackEntryCount() > 0)
{
getSupportFragmentManager().popBackStack();
}
else
{
super.onBackPressed();
}
}
Update:
add your line updateToolbar(); below pop call inside if statement.
Answer is similar to Sarthak's, however instead of calling:
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
}
else {
super.onBackPressed();
}
call the instance of YOUR fragment manager i.e fragmentManager
like so:
if (fragmentManager.getBackStackEntryCount() > 0) {
fagmentManager.popBackStack();
}
else {
super.onBackPressed();
}
UPDATE:
Probably best to create a FragmentManager field, initialise it in the onCreate of your activity and then use that throughout all fragment transactions, adding to back stack and so on.

Android fragments and the backstack

I am building an android app that uses a drawer navigation and it looks and works well except i cant add the current view (fragment) to the back stack to get allow the user navigate the app more easily. at the moment the back button just exits the app when pressed. i have looked at various questions on here and none have worked.
Here is my current attempt and dont understand why it dosent work.
if (id == R.id.nav_gallery) {
// fragmentManager.beginTransaction().replace(R.id.content_frame, new GalleryFragment()).commit();
// fragmentManager.beginTransaction().addToBackStack(null);
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, new GalleryFragment());
ft.addToBackStack(null);
ft.commit();
}
edit
onbackPressed
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
FragmentManager fragmentManager = getFragmentManager();
int backCount = fragmentManager.getBackStackEntryCount();
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
if you want to control your transaction when back button pressed of android then use below code
#Override
public void onBackPressed() {
// initialize variables
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
// check to see if stack is empty
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
ft.commit();
}
else {
if (this.lastBackPressTime < System.currentTimeMillis() - 4000) {
Toast.makeText(this, "Nochmal drücken zum Beenden!", 4000).show();
this.lastBackPressTime = System.currentTimeMillis();
} else{
super.onBackPressed();
}
}
}
instead of doing
super.onBackPressed();
Pop the top state off the back stack using the below condition
if(backCount >0){
fragmentManager.popBackStack();
}else{
super.onBackPressed();
}
Can you please try this one ?
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, new GalleryFragment());
ft.addToBackStack("gallery_fragment");
ft.commit();
Hope this will help you.

Categories

Resources