popBackStack remove all stack? - android

I have one activity. This activity has a view pager. This viewpager has five pages and these pages open a fragment in their contents. The problem occurs, for example, when I open two fragments in the first page and then open one fragment in a second page. I go back to first page. I click back button in toolbar. And I use popBackStack() code to remove fragment which is visible currently.
But it removes all backstacks. How can I solve this?
getSupportFragmentManager().popBackStack(str,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
My algorithm :
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home){
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
if(getSupportFragmentManager() != null){
int count = getSupportFragmentManager().getBackStackEntryCount();
Log.i("Fragment Stack Count : ", count+"");
if (count <= 0) {
super.onBackPressed();
} else {
checkBackStack();
}
}
}
private void checkBackStack(){
Log.i("BackStack", "Home Activity Count > 0");
FragmentManager fm= getSupportFragmentManager();
if(fm.getBackStackEntryCount() > 0){
Log.i("BackStack", "Count > 0");
for(int i = (fm.getBackStackEntryCount()-1) ; i >= 0 ; i--){
FragmentManager.BackStackEntry backStackEntry = fm.getBackStackEntryAt(i);
String str= backStackEntry.getName();
Log.i("BackStack", " Name : "+str);
BaseMenuFragment fragment= (BaseMenuFragment) fm.findFragmentByTag(str);
if(((ViewGroup) fragment.getView())!= null && ((ViewGroup) fragment.getView().getParent()) != null){
int contentId = ((ViewGroup) fragment.getView().getParent()).getId() ;
if(contentId == frames[viewPager.getCurrentItem()]){
Log.i("BackStack", "equals = true");
getSupportFragmentManager().popBackStack(str, FragmentManager.POP_BACK_STACK_INCLUSIVE);
return;
}
}
}
}
}

I think this can help you. I've faced this some time ago and I found a solution.
This is not a library, it is a demo app. I'm sorry if the structure is
Eclipse-like. It's been a while I did this.

Related

How to go back to a previous viewpager fragment from an activity?

I know there are similar questions to the one I'm asking but none of them was able to solve the issue I'm having.
I Have a bottom navigation view with five fragments that use viewpager, one of these fragments opens an activity.
Problem
When I open the activity from the fragment it works fine but the issue is the when I press back it goes back to the same fragment that opens the activity.
Solution
I want when I press back out of the activity that it goes to a previous fragment apart from the fragment that calls the activity.
For example: if the user is on HomeFragment and the user clicks the fragment that opens the activity(NewsFragment), and the user press back they Should go back to HomeFragment, not NewsFragment.
What I tried so far:
MainActivity for the BottomnNvigationView and it's On Back Press
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.nav_library:
viewPager.setCurrentItem(0);
temp = temp.replace("-0", "") + "-0";
break;
case R.id.nav_technology:
viewPager.setCurrentItem(1);
temp = temp.replace("-1", "") + "-1";
break;
case R.id.nav_home:
viewPager.setCurrentItem(2);
temp = temp.replace("-2", "") + "-2";
break;
case R.id.nav_science:
viewPager.setCurrentItem(3);
temp = temp.replace("-3", "") + "-3";
break;
case R.id.nav_news:
viewPager.setCurrentItem(4);
temp = temp.replace("-4", "") + "-4";
Intent intent = new Intent(MainActivity.this,BrowserActivity.class);
startActivity(intent);
return true;
}
return true;
}
};
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout)findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else {
String[] words = temp.split("-");
if(words.length<=2)
if (viewPager.getCurrentItem() != 2) {
temp = "";
viewPager.setCurrentItem(2);
}else
finish();
else {
temp = temp.replace("-" + words[words.length - 1], "");
int pos = viewPager.getCurrentItem();
if (viewPager.getCurrentItem() == pos)
pos = 2;
else
pos = 1;
viewPager.setCurrentItem(Integer.parseInt(words[words.length - pos]));
}
}
}
The Activity that is call from the fragment (BrowersActivity) On Back Press
#Override
public void onBackPressed() {
if (viewPager.getCurrentItem() != 0) {
viewPager.setCurrentItem(viewPager.getCurrentItem() - 1,false);
}else{
finish();
}
}
Any help would be appreciated.
Quickest solution would be to finish the first activity after starting the second one so:
case R.id.nav_news:
viewPager.setCurrentItem(4);
temp = temp.replace("-4", "") + "-4";
Intent intent = new Intent(MainActivity.this,BrowserActivity.class);
startActivity(intent);
finish()
return true;
And in the second activity in onBackPressed, restart the first activity
#Override
public void onBackPressed() {
super.onBackPressed()
startActivity(new Intent(this, FirstActivity.class))
}

ViewPager - Launch Activity from setOnTabSelectedListener

I'm trying to get an activity to launch when a specific tab is selected but when I return from that activity, I want the previous to show instead of the tab I clicked. Just like when you click the plus button on Instagram.
Like this:
Default Fragment 1/Tab 1
Go to Fragment 5/Tab 5
Click tab 3, activity pops up
Go back, see Fragment 5/Tab 5
Right now, I'm storing the last visited tab index in a variable, then when Tab 3 is clicked, it just goes to the last visited tab.
tabLayout.setOnTabSelectedListener(
new TabLayout.ViewPagerOnTabSelectedListener(viewPager) {
#Override
public void onTabSelected(TabLayout.Tab tab) {
//super.onTabSelected(tab); -- Should keep this or leave it commented out?
int pos = tab.getPosition();
switch (pos) {
case 0:
viewPager.setCurrentItem(tab.getPosition(), false);
getSupportActionBar().setTitle("Home");
pre_pos = pos;
pre_title = "Home";
break;
case 1:
viewPager.setCurrentItem(tab.getPosition(), false);
getSupportActionBar().setTitle("Trending");
pre_pos = pos;
pre_title = "Trending";
break;
case 2:
viewPager.setCurrentItem(pre_pos, false);
getSupportActionBar().setTitle(pre_title);
Intent intent = new Intent(MainActivity.this, NewEvent_Activity.class);
startActivity(intent);
Toast.makeText(getApplicationContext(),
"Curr: "+ viewPager.getCurrentItem()+
" Prev: " + pre_pos +
" Clicked: " +tab.getPosition(),
Toast.LENGTH_SHORT).show();
break;
case 3:
viewPager.setCurrentItem(tab.getPosition(), false);
getSupportActionBar().setTitle("Notifications");
pre_pos = pos;
pre_title = "Notifications";
break;
case 4:
viewPager.setCurrentItem(tab.getPosition(), false);
getSupportActionBar().setTitle("Profile");
pre_pos = pos;
pre_title = "Profile";
break;
}
}
});
In ViwPager.java it calls this function when setCurrentItem() is called
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
if (mAdapter == null || mAdapter.getCount() <= 0) {
setScrollingCacheEnabled(false);
return;
}
//I think my problem lies in the following line (mCurItem == item)
if (!always && mCurItem == item && mItems.size() != 0) {
setScrollingCacheEnabled(false);
return;
}
if (item < 0) {
item = 0;
} else if (item >= mAdapter.getCount()) {
item = mAdapter.getCount() - 1;
}
final int pageLimit = mOffscreenPageLimit;
if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
// We are doing a jump by more than one page. To avoid
// glitches, we want to keep all current pages in the view
// until the scroll ends.
for (int i = 0; i < mItems.size(); i++) {
mItems.get(i).scrolling = true;
}
}
final boolean dispatchSelected = mCurItem != item;
if (mFirstLayout) {
// We don't have any idea how big we are yet and shouldn't have any pages either.
// Just set things up and let the pending layout handle things.
mCurItem = item;
if (dispatchSelected) {
dispatchOnPageSelected(item);
}
requestLayout();
} else {
populate(item);
scrollToItem(item, smoothScroll, velocity, dispatchSelected);
}
}
I think this is where my problem is but I can't edit it.
Any suggestions?
Thanks.
implement ViewPager.OnPageChangeListener on activity. set listner on viewpager
view_pager.setOnPageChangeListener(this);
in OnPageSelected() method:
#Override
public void onPageSelected(int position) {
if (position == 3) {
startActivity(new Intent(this,activity.class));
}
}
override activity onResume method and write:
#Override
public void onResume() {
super.onResume();
view_pager.setCurrentItem(0);
}
To do this You have to follow these Simple Steps
Step : 1 Override below method in all ViewPager Frgment
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
}
this method will be called when your fragment become visible.
step : 2 Put a condition in Fragmenr3 to start new Activity when your Fragment become visible
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
if(menuVisible){
Intent intent = new Intent(MainActivity.this, NewEvent_Activity.class);
startActivity(intent);
}
}
Now it will open you activity in front. but your one requirement remaining which is, if user press back from activity, you have to show second Last fragment, so as you have mention you are storing index position of Last fragment so follow below step .
Step : 3 Override onRestart() in Your ViewPager Actvity
#Override
protected void onRestart() {
super.onRestart();
view_pager.setCurrentItem(Stored last Index);
}
it will solve your problem, its working for me.

Fragment Page stack count always 0 in android

I am trying to go back to the previous fragments when click back button. If there is no pages available in page stack it should show press back again to exit.
I am trying like this.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
int pageCount = getFragmentManager().getBackStackEntryCount();
if (pageCount != 0) {
this.getFragmentManager().popBackStack();
return true;
}
else
{
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return true;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
}
return super.onKeyDown(keyCode, event);
}
Here I check the page count. But it always showing 0.
I always add this line in all fragment.replace
FragTrans.addToBackStack(null);
Please help me to resolve the problem. When I click the back button It should go to the previous page. If there is no pages is available mean it should show the toast message.
Try it, Use fragment.add instead of fragment.replace. it will allow to
maintain your all Fragments to back stack. If you are using
fragment.replace then it will maintain only one fragment in stack.
Sample Code:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
HelloFragment hello = new HelloFragment();
fragmentTransaction.add(R.id.fragment_container, hello, "HELLO");
fragmentTransaction..addToBackStack("optional tag");
fragmentTransaction.commit();

Popbackstack Finishes Activity in OnBackPressed

I have an Activity with two Fragments (List & Details), in onCreate(), I start the List Fragment if savedInstance is null like so
public static final int CLIENT_LIST_FRAGMENT = 1;
public static final int CLIENT_DETAILS_FRAGMENT = 2;
private int currentFragment = 0;
if (savedInstanceState == null) {
//On first run, start the list fragment
if (currentFragment == 0) {
ClientListFragment listFrag = new ClientListFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.container_client, listFrag, Constants.CLIENT_LIST_FRAGMENT_TAG)
.commit();
currentFragment = CLIENT_LIST_FRAGMENT;
} else {
switch (currentFragment) {
case CLIENT_LIST_FRAGMENT:
addListFragment();
break;
case CLIENT_DETAILS_FRAGMENT:
addDetailsFragment(0);
break;
}
}
}
And here is the method that add the DetailsFragment and ListFragment as needed
private void addListFragment(){
ClientDetailsFragment listFrag = new ClientDetailsFragment();
getSupportFragmentManager().beginTransaction()
.replace(R.id.container_client, listFrag, Constants.CLIENT_LIST_FRAGMENT_TAG)
.addToBackStack("details")
.commit();
currentFragment = CLIENT_LIST_FRAGMENT;
}
private void addDetailsFragment(long companyId){
ClientDetailsFragment detailsFrag = ClientDetailsFragment.newInstance(companyId);
getSupportFragmentManager().beginTransaction()
.replace(R.id.container_client, detailsFrag, Constants.CLIENT_DETAILS_TAG)
.addToBackStack(null)
.commit();
currentFragment = CLIENT_DETAILS_FRAGMENT;
}
This works as expected except that when I click the back button from the Details Fragment, instead of taking me back to the List Fragment, it actually finishes the Activity. It goes back to the List Fragment for a split second and then finishes the host Activity and goes back to the calling Activity. How can I stop this behavior, after going through a lot of onBackpress related question on SO here is my overide of the onBackPressed
#Override
public void onBackPressed() {
if (currentFragment == CLIENT_DETAILS_FRAGMENT){
getSupportFragmentManager().popBackStackImmediate();
}else {
super.onBackPressed();
}
}
Thanks
Activity onBackPressed() should be:
For android.support.v4.app.Fragment
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 1)
getSupportFragmentManager().popBackStack();
else
finish();
}
For android.app.Fragment
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 1)
getFragmentManager().popBackStack();
else
finish();
}
I usually check whether the current fragment instance belongs to the fragment that invoked onBackPressed(). This code is untested; it's just to give you an idea on how to proceed. I hope you are not calling this.finish() on this Activity.
#Override
public void onBackPressed() {
Fragment fragment = getSuportFragmentManager().findFragmentByTag(Constants.CLIENT_DETAILS_TAG);
if (fragment instanceof ClientDetailsFragment) {
getSupportFragmentManager().popBackStackImmediate();
}
else {
super.onBackPressed();
}
}
Let me know if that helps.
Good Lord, I was chasing the wrong shadow for two days. I was listening, handling and overriding the wrong event.
This SO question saved me Why is onBackPressed() not being called?
And the gist is "onBackPressed() is invoked when user clicks on a hardware back button (or on the 'up' button in the navigation bar), not the button in the action bar. For this one you need to override onOptionsItemSelected() method. Example:"
I was catching this event the fragment and calling getActivity.onBackpressed. When I stopped this, it became obvious to me that the onBackPressed is not being called. Here is my solution, may not be optimal but it works
if (item.getItemId() == android.R.id.home){
if (currentFragment == CLIENT_DETAILS_FRAGMENT){
getSupportFragmentManager().popBackStackImmediate();
currentFragment = CLIENT_LIST_FRAGMENT;
return true;
}
}
if (currentFragment == 0) {
ClientListFragment listFrag = new ClientListFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.container_client, listFrag, Constants.CLIENT_LIST_FRAGMENT_TAG)
.commit();
currentFragment = CLIENT_LIST_FRAGMENT;
}
while changing this add to addToBackStack()
and,
change onBackPressed() like,
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 1) {
MainActivity.this.finish();
}
else {
getFragmentManager().popBackStack();
}
}
Hope, this will work.

Android : Return to previous fragment on back press

I have implemented Navigation Drawer which is a subclass of Activity. I have many fragments in my application. My question goes here
Imagine there are 3 fragments :
Fragment_1 : Fragment_2 : Fragment_3
When I start my application, Fragment_1 is loaded
When I click on some components on Fragment_1, I'm navigated to Fragment_2 and so on..
So it's like
Fragment_1 > Fragment_2 > Fragment_3
When I press back key from Fragment_2, I'm navigated back to Fragment_1
But when I press back key from Fragment_3, I'm navigated back to Fragment_1 (instead of Fragment_2)
I want something like this in my application on Back Key press
Fragment_1 < Fragment_2 < Fragment_3
I have used Fragment, FragmentManager, FragmentTransaction as follows :
MyFragment fragment = new MyFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).addToBackStack(null)commit();
and I tried overriding onBackPressed() in my MainActivity :
#Override
public void onBackPressed() {
getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0)
super.onBackPressed();
}
Update your Activity#onBackPressed() method to:
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
The reason your implementation doesn't work is because the method FragmentManager#popBackStack() is asynchronous and does not happen right after it is called.
From the documentation:
This function is asynchronous -- it enqueues the request to pop, but the action will not be performed until the application returns to its event loop.
Reference: http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack(java.lang.String,%20int)
You have to implement your own backstack implementation as explained here
Separate Back Stack for each tab in Android using Fragments
You can call the popFragments() whenever you click the back button in a fragment and call pushFragments() whenever you navigate from one Fragment to other.
in Short,
public void onBackPressed()
{
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.popBackStack();
}
The tric is in FragmentManager#executePendingTransactions();.
This is what I use for nested fragments as well...:
/**
* if there is a fragment and the back stack of this fragment is not empty,
* then emulate 'onBackPressed' behaviour, because in default, it is not working.
*
* #param fm the fragment manager to which we will try to dispatch the back pressed event.
* #return {#code true} if the onBackPressed event was consumed by a child fragment, otherwise
*/
public static boolean dispatchOnBackPressedToFragments(FragmentManager fm) {
List<Fragment> fragments = fm.getFragments();
boolean result;
if (fragments != null && !fragments.isEmpty()) {
for (Fragment frag : fragments) {
if (frag != null && frag.isAdded() && frag.getChildFragmentManager() != null) {
// go to the next level of child fragments.
result = dispatchOnBackPressedToFragments(frag.getChildFragmentManager());
if (result) return true;
}
}
}
// if the back stack is not empty then we pop the last transaction.
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
fm.executePendingTransactions();
return true;
}
return false;
}
and in my onBackPressed :
if (!FragmentUtils.dispatchOnBackPressedToFragments(fm)) {
// if no child fragment consumed the onBackPressed event,
// we execute the default behaviour.
super.onBackPressed();
}
Use this code on tab change in your main activity to clear the stack.
int count = getFragmentManager().getBackStackEntryCount();
if(count>0){
for (int i = 0; i <count; i++) {
getFragmentManager().popBackStack();
}
}
Then on Back pressed of your main activity do this
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onbackpressed();
}
else {
getFragmentManager().popBackStack();
}
}
Here is working and tested code by me, This will help you
private static final int TIME_INTERVAL = 2000;
private long mBackPressed;
private void applyExit() {
if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) {
finish();
} else {
Toast.makeText(this,"Press Again to exit",Toast.LENGTH_LONG).show();
}
mBackPressed = System.currentTimeMillis();
}
#Override
public void onBackPressed() {
fm = getSupportFragmentManager();
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
if (fm.getFragments().size() <= 1) {
applyExit();
} else {
for (Fragment frag : fm.getFragments()) {
if (frag == null) {
applyExit();
return;
}
if (frag.isVisible()) {
FragmentManager childFm = frag.getChildFragmentManager();
if (childFm.getFragments() == null) {
super.onBackPressed();
return;
}
if (childFm.getBackStackEntryCount() > 0) {
childFm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
return;
} else {
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
return;
}
}
}
}
}

Categories

Resources