android Fragment popBackStack confusion - android

I have a lot of Fragments. e.g: A1,A2,A3, B1,B2,C1,C2,C3. All Fragments were in a container,FActivity.
I hoped when current Fragment was A1 or B1 or c1 I press the back key,the project finished.
I follwed this order to hide previous one and show next one, and all of them were addToBackStack.But when I call FActivity.onBackPressed(), I found the popBack not restoring previous fragment and feel confused.some fragment were missed.Especially B1 and C1 were not in the backstack. They were missed.
here is my hide&show code:
private void showFragment(FragmentTransaction ft1, Fragment fm1, Fragment fm2, String tag) {
if (fm1 != null) {
if (!fm1.isAdded()) {
ft1.add(R.id.information_detail, fm1).hide(fm1);
} else {
ft1.hide(fm1);
}
ft1.addToBackStack(tag);
}
if (!fm2.isAdded()) {
ft1.add(R.id.infomation_detail, fm2, tag);
} else {
ft1.show(fm2);
}
ft1.commit();
}
fragment control
Fragment currentFragment ;
public void startFragmentOnParameter(Fragment oldFragment, String tag, String... param) {
FragmentTransaction ft1 = getFragmentManager().beginTransaction();
switch (tag) {
case "A1":
A1= new A1();
showFragment(ft1,oldFragment, A1, true, "A1");
currentFragment = mPatientCaseInHistory;
break;
case "A2":
A2= new A2();
showFragment(ft1, oldFragment, A2, false, "A2");
currentFragment = mPatientWithArrear2;
break;
case "A3":
A3= new A3();
showFragment(ft1, oldFragment, A3, false, "A3");
currentFragment = mPatientsCases3;
break;
......
}
and onBackPressed
public void onBackPressed() {
String name = currentFragment.getClass().getSimpleName();
if(name.equals("A1")||name.equals("B2")||name.equals("C1")){
finish();
}else{
super.onBackPressed();
currentFragment = (Fragment) getFragmentManager().findFragmentById(R.id.infomation_detail);
}
}
What's wrong in my code?

Try to use
getFragmentManager().popBackStack();
instead
super.onBackPressed();

Related

Maintaining BackStack In Bottom Navaigation

I am using bottomNavigation in my android app. I have 5 fragments A, B, C, D, E. The fragment B contains another fragment says B1. When I backpress on fragment B1, it closes the app. How can I move to fragment B when backpressed from fragment B1.
Here is my code
bottomNavigationView.setOnNavigationItemSelectedListener(
item -> {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.A:
fragment = new A();
break;
case R.id.B:
fragment = new B();
break;
case R.id.C:
fragment = new C();
break;
case R.id.D:
fragment = new D();
break;
case R.id.E:
fragment = new E();
break;
}
return loadFragment(fragment);
});
private boolean loadFragment(Fragment fragment) {
//switching fragment
if (fragment != null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.main_fragment, fragment)
.commit();
return true;
}
return false;
}
While opening B1 Fragment use this
private boolean loadFragmentB1(Fragment fragment) {
//switching fragment
if (fragment != null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.main_fragment, fragment)
.commit();
return true;
While opening other fragment except B1 , use this
private boolean loadFragment(Fragment fragment) {
//switching fragment
if (fragment != null) {
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(null)
.replace(R.id.main_fragment, fragment)
.commit();
return true;
}
return false;
}
And on activity override onBackPressed like this
#Override
public void onBackPressed(){
if (getSupportFragmentManager().getBackStackEntryCount() != 0) {
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
finish();
}
}

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().

How to go to an activity's fragment from an another activity?

I have a DrawerMenuActivity suppose "AA" and it has 3 fragments "A", "B" and "C" as it's menu. Fragment "A" is my default screen. Now i have navigated to the fragment "B" which has listview items and each item click will open another new activity "AB". In AB there will be a button and that button click will open another activity "AC". so Basically the flow is as follows,
From AA(DrawerMenuActivity) -> "A" fragemnt -> "B" or "C" fragments -> AB(Activity) -> AC(Activity)
Now what i want to do is to return to fragment "B" from the Activity "AC".
I have replaced the fragments of Activity "AA" like this,
in OnCreate(),
if (savedInstanceState == null) {
A fragment = new A();
replaceFragment(fragment, false, Constants.HOME_FRG_TAG);
Handler handler = new Handler(Looper.getMainLooper());
Runnable runnable = new Runnable() {
#Override
public void run() {
if (getIntent().getStringExtra("FROM AC") != null) {
updateDisplay(1);
}
}
};
handler.postDelayed(runnable, 10);
}
and for replacing fragments,
public void updateDisplay(int position) {
Fragment fragment = null;
String tag = null;
switch (position) {
case 0:
clearStack();
mDrawerLayout.closeDrawer(mDrawerList);
break;
case 1:
fragment = new B();
tag = "B";
break;
case 2:
fragment = new C();
tag = "C";
break;
default:
break;
}
if (fragment != null) {
replaceFragment(fragment, true, tag);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
Log.e("Activity", "Error in creating fragment");
}
}
replaceFragment() function,
public void replaceFragment(Fragment newFragment, boolean backStackTag, String fragmentTag) {
try {
Fragment selectedFrag = getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (selectedFrag != null && selectedFrag.isVisible()) {
return;
}
FragmentManager fm = AA.this.getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
if (backStackTag) transaction.addToBackStack(null);
transaction.commit();
} catch (Exception e) {
Log.e("exception ", " on adding fragment");
// TODO: handle exception
}
}
and clearStack(),
public void clearStack() {
FragmentManager fm = AA.this.getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
in AC Activity i have tried to come back to fragment "B" like this,
Intent in = new Intent(AC.this, AA.class);
in.putExtra("FROM AC", "from ac");
startActivity(in);
now this does what i intend to do but the problem is when it is loading fragment "A" opens for a brief time and then it comes back to the fragment "B".
How Do i navigate to fragment "B" from Activity "AC" properly?? please any help would be appreciated...!!
First when you go from AB to AC start it as with startActvityForResult, and make sure you don't pass the clear backstack flags. Do it just like this:
public static final int REQ_CODE = 1;
Intent in = new Intent(this, AB.class);
startActivityForResult(in, REQ_CODE);
So the backstack is not cleared. When replacing the fragments in AA do it like this:
public void replaceFragment(Fragment newFragment, boolean backStackTag, String fragmentTag) {
try {
Fragment selectedFrag = getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (selectedFrag != null && selectedFrag.isVisible()) {
return;
}
FragmentManager fm = AA.this.getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.container, fragmentB).commit();
} catch (Exception e) {
Log.e("exception ", " on adding fragment");
// TODO: handle exception
}
}
And when you want to get back from activity AC, set the result to RESULT_OK if you want to navigate back to AA or RESULT_CANCELED if not.
setResult(Activity.RESULT_OK);
finish();
In AB, override the onActivityResult method so it sends you back to AA:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQ_CODE) {
if (resultCode == RESULT_OK) {
finish();
}
}
}
so if RESULT_OK is passed, it will go back to AA where the activity was still in onStop() and the state was saved. Also make sure to init your views in onCreate and not in onStart.
Use startActivityForResult to pass params from AC to AA.It's a little complicated.EventBus may be helpful to you.

FragmentManager.findFragmentByTag always returns null

I have an Activity in which I switch the content by replacing a Fragment.
In the onCreate of this Activity, I set the first Fragment with this code:
fm.beginTransaction().add(R.id.container, new FooFragment(), "f_0").commit();
After that, I want to switch this Fragment by another one depending on an Integer (I use a drawer), here is the code:
int position = //I get my index here
Fragment f = fm.findFragmentByTag("f_" + position); //(1)
if (f == null) {
switch (position) {
case 0:
f = new FooFragment();
break;
case 1:
f = new BarFragment();
break;
//Etc...
}
}
//Then I replace the actual Fragment by the new one
fm.beginTransaction()
.replace(R.id.container, f, "f_" + position)
.commit();
My problem is that the code on (1) always return null so every time I change the Fragment, it creates a new instance. I want to have at any time only one instance of each Fragment type.
Thanks.
Set first fragment:
getSupportFragmentManager().beginTransaction().addToBackStack("f_0").replace(R.id.container, new FooFragment(), "CURRENT_FRAGMENT_TAG").commit();
Use this function to replace fragments:
public void replaceFragment(Fragment fragment, String tag) {
Fragment currentFragment = getSupportFragmentManager().findFragmentByTag("CURRENT_FRAGMENT_TAG");
//to avoid adding the same fragment, you can use 'instanceof' instead of comparator
if (currentFragment.getClass() == fragment.getClass()) {
return;
}
getSupportFragmentManager().popBackStack(tag, FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(tag).replace(R.id.container, fragment, "CURRENT_FRAGMENT_TAG")
.commit();
}
Example execution:
replaceFragment(new FooFragment(), "f_" + position);
Override onBackPressed.
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
finish();
} else {
super.onBackPressed();
}
}

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