Android: Check if fragment exits in Stack and reuse it - android

Hi I am using a Stack variable for storing the sequence of fragments clicked by the user
For example : [A,B,C,A,D]
Now I need to check if a fragment exits in the stack I need to reuse it.
From the above example I need to reuse the first element i.e, A when user clicks on the fourth time.
The problem is I have a custom keyboard opening in fragment A, now if the same fragment is in the stack as forth element the keyboard is not opening .but when I backpress and go to first element keyboard is opened in the first instance of A
Code for storing in the Stack
public void switchContent(Fragment fragment) {
if(mContent !=null && (fragment.getClass().toString().equals(mContent.getClass().toString()))){
getSlidingMenu().showContent();
return;
}
mContent = fragment;
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(R.id.content_frame, mContent);
FragmentChangeActivity.fragmentStack.lastElement().onPause();
FragmentChangeActivity.fragmentStack.push(mContent);
ft.commit();
getSlidingMenu().showContent();
}
Code for backpress
#Override
public void onBackPressed() {
if (fragmentStack.size() >= 2) {
FragmentTransaction ft = fragmentManager.beginTransaction();
fragmentStack.lastElement().onPause();
ft.remove(fragmentStack.pop());
fragmentStack.lastElement().onResume();
ft.show(fragmentStack.lastElement());
ft.commit();
} else {
super.onBackPressed();
}
}
Any help is appreciated.

The following code check's if Fragment named SearchFragment exists or not in backstack and processes accordingly. You can use this logic to determine if a specific Fragment exists or not
FragmentManager fragmentManager=getSupportFragmentManager();
Fragment currentFragment = (Fragment)fragmentManager.findFragmentById(R.id.mainContent);
if(currentFragment!=null && currentFragment instanceof SearchFragment){
//SearchFragment exists in backstack , process accordingly
}else{
//SearchFragment not present in backstack
}

Related

Memory leak on fragment transaction

I have two fragments one list and one detail fragment. On list item click I a hiding list fragment and adding detail fragment on back press detail fragment is popped automatically I am just calling super.onBackPressed() but issue is it is creating so many references of detail fragments resulting is memory leaks
Following is my code
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.hide(this);
ft.add(containerId, detailFragment, "detail");
ft.addToBackStack("detail");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
I don't want to view to be recreated view when user press back button on detail fragment thats why I used above approach. Also with current implementation when I press back button recylerview scroll possition and other data I don't have to save
My Activity has only following code it inflates list fragment
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.FragmentContainer1, ListFragment.newInstance(), TAG).commit();
}
I think what you are doing wrong is that you are adding fragments each time to the container again and again by calling add method:
In your case you should use replace method and add your list fragment to the backstack. Here's how you should start your detail fragment:
FragmentManager fm = getFragmentManager();
fm.beginTransaction()
.replace(R.id.container, new DetailFragment())
.addToBackstack(null)
.commit();
To get back to your list fragment, which is in the back stack, just call:
fm.popBackStack();
EDIT:
Try this to show your list fragment:
protected void displayListFragment() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (listFragment.isAdded()) {
ft.show(listFragment);
} else {
ft.add(R.id.flContainer, listFragment, "ListFragment");
}
if (detailFragment.isAdded()) {
ft.remove(detailFragment);
}
ft.commit();
}
And this to show your detail fragment:
protected void displayDetailFragment() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (listFragment.isAdded()) {
ft.hide(listFragment);
}
if (!detailFragment.isAdded()) {
ft.add(R.id.flContainer, detailFragment, "DetailFragment");
}
ft.commit();
}

Android fragment handling back button

I am creating an application with multiple fragments. I have four fragments fragment1, fragment2, fragment3, fragment4. I am moving from different orders like f1 -> f2 -> f4 -> f3 -> f1 or any other order. But when I click the back button from each fragment I need to go to the previous fragment. How to handle this.
Edit 1:
I already tried
FragmentManager fm = ((Activity) context).getFragmentManager();
for (int i = 0; i < fm.getBackStackEntryCount(); i++) {
fm.popBackStack();
}
Which is not help me to solve my issue.
Sample code of Manage Fragment back stack
private Stack<Fragment> stack = new Stack<Fragment>();
public void pushFragments(Fragment fragment, boolean shouldAnimate,
boolean shouldAdd) {
drawerClose = false;
if (shouldAdd)
stack.push(fragment);
this.changeFragment = fragment;
invalidateOptionsMenu();
changeFragment(fragment, shouldAnimate, false);
}
public void popFragments() {
/*
* Select the second last fragment in current tab's stack.. which will
* be shown after the fragment transaction given below
*/
Fragment fragment = stack.elementAt(stack.size() - 2);
// / pop current fragment from stack.. /
stack.pop();
/*
* We have the target fragment in hand.. Just show it.. Show a standard
* navigation animation
*/
this.changeFragment = fragment;
invalidateOptionsMenu();
changeFragment(fragment, false, true);
}
private void changeFragment(Fragment fragment, boolean shouldAnimate, boolean popAnimate) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
if (shouldAnimate)
ft.setCustomAnimations(R.anim.slide_in_right,
R.anim.slide_out_left);
if (popAnimate)
ft.setCustomAnimations(R.anim.slide_in_left,
R.anim.slide_out_right);
ft.replace(R.id.content_frame, fragment);
ft.commit();
}
//On BackPress just check this thing
private void backManage() {
if (stack.size() > 1) {
popFragments();
}
}
Use addToBackStack(String tag), while committing the fragment to add the fragment into the stack of your application:
getFragmentManager().beginTransaction().replace(fragmentContainer.getID(), fragment)
.addToBackStack(null).commit();`
on Activity
#Override
public void onBackPressed() {
if(check_if_backstack_is_null)
super.onBackPressed();
else
{
popupFromBackstack();
}
}
You should override onBackPressed method:
#Override
public void onBackPressed() {
if (fragment != null && fragment.getChildFragmentManager().getBackStackEntryCount() > 0){
fragment.getChildFragmentManager().popBackStack();
}else {
super.onBackPressed();
}
}
For this you can set addToBackStack to fragment transation and then call commit.
By calling addToBackStack(), the replace transaction is saved to the back stack so the user can reverse the transaction and bring back the previous fragment by pressing the Back button.
If you add multiple changes to the transaction (such as another add() or remove()) and call addToBackStack(), then all changes applied before you call commit() are added to the back stack as a single transaction and the Back button will reverse them all together.
You just need to add addToBackStack(null) by FragmentTransaction.
when you are calling next Fragment just add this method with null parameter.
Like this.
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(..............);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Use this lines of code for it:-
#Override
public void onBackPressed() {
if ( getSupportFragmentManager().getBackStackEntryCount() > 0){
fm.popBackStack();
}else {
super.onBackPressed();
}
}
To get the backStack functionality in your fragmentthan you should have use the .addToBackStack(null) , while performing the fragment transaction like below:-
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.YOUR_CONTAINER, YOUR_FRAGMENT,"TAG")
.addToBackStack(null) /// IT IS NECESSARY TO GET THE BACK STACK PROPERTY IN YOUR FRAGMENT
.commitAllowingStateLoss();

Back in fragment and nested fragment

i have app like this
one activity and inside it >
fragment a (loaded when run app also from menu can open it )
fragment b (open it from just menu)
fragment c (can open it from fragment a and also can open it from menu)
also inside fragment c there are 4 child fragments
in main activity(using navigation drawer as source) i call fragment a in oncreate like this
FragmentManager fragmentManager=getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.fragment_place,new First_Fragment()).addToBackStack("First").commit();
my problem is how to control back button to always back to fragment a and when fragment a is open close app
i was using addToBackStack(null) but is not what i want because will show all history of fragments that i opened
When adding fragment a to the back stack "addToBackStack(String name)" pass in a name.
Then listen for on back presses in your fragments
FragmentManager fm = getFragmentManager();
fm.addOnBackStackChangedListener(new OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
}
});
make sure to stop listening when each fragment is not being shown.
Then you can pop back to the named fragment added to the back stack
FragmentManager fm = getActivity()
.getSupportFragmentManager();
fm.popBackStack ("name", FragmentManager.POP_BACK_STACK_INCLUSIVE);
Make sure the rest of your fragment transactions are not added to the back stack. This should give you the behavior you want.
addToBackStack(String tag) is used to add the fragment to backstack and it contains the string as parameter. This parameter can be null or have some value.
If you pass null, it will add your fragment to backstack with tag null. addToBackStack(null) doesn't mean that your fragment is not added to backstack.
If you want your fragment will not be added to backstack, then just delete this line.
If you are adding your fragment to backstack and want it to be visible onBackPressed, then you can use
getSupportFragmentManager().popBackStackImmediate(/* Fragment TAG */,0);
CODE:- Try the below code and let me know.
Copy the below function in your main Activity.
/**
* function to show the fragment
*
* #param name fragment to be shown
* #param tag fragment tag
*/
public void showFragment(Fragment name, String tag) {
FragmentManager fragmentManager = getSupportFragmentManager();
// check if the fragment is in back stack
boolean fragmentPopped = fragmentManager.popBackStackImmediate(tag, 0);
if (fragmentPopped) {
// fragment is pop from backStack
} else {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, name, tag);
fragmentTransaction.addToBackStack(tag);
fragmentTransaction.commit();
}}
Show fragment using the below code.
showFragment(yourFragment, yourFragmentTag);
In mainActivity onBackPressed.
#override
public void onBackPressed(){
FragmentTransaction fts = getSupportFragmentManager().beginTransaction();
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() >= 2) {
// always show your fragment a here
showFragment(new FragmentA(), FragmentA.class.getSimpleName());
} else {
// finish your activity
}
}

Fragment back stack, android?

My activity consists of navigation drawer and currently have 5 options in the left menu. Which all opens in fragment.
I am looking for a way to keep a stack of all the fragments so when the user presses back button he moves to previous fragment.
Like- Activity consists of drawer menu which have 5 options menu1, menu2, menu3, menu4, menu5 having corresponding fragments F1, F2, F3, F4, F5.
User presses menu1 he is forwarded to F1
Then presses menu2, and then menu4.
When the user is at F4 and he presses back he should be moved to F2 rather than exiting the activity or app.
How can it implemented and example or sample code preferred.
I currently use this code but it does not help me out
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment)
.addToBackStack(null)
.commit();
I found some workaround for your query :
Override onBackPressed() in code
Use methods related to backstack maintained which contains your all fragment transactions
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack(); // this will display last visible fragment
getActinBar().setTitle(mTitle); // save your title in some variable and restore here
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed(); // system will handle back key itself
}
}
Reference answer : this
I used to replace Fragment like as below :
public void replaceFragment(Fragment fragment, boolean addToBackStack, int transition) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.activity_main_relative_container, fragment, fragment.getClass().getName());
ft.setTransition(transition);
if (addToBackStack) {
ft.addToBackStack(fragment.getClass().getName());
}
ft.commitAllowingStateLoss();
}
// While to replace Fragment
replaceFragment(mFragment, true, FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
// False for not adding Fragment in back stack and true to add.
Hope this helps.
You need to add fragment to backstack
private FragmentTransaction m_fragmentTransaction;
FragmentOne m_fragOne = new FragmentOne();
m_fragmentTransaction = m_fragmentManager.beginTransaction();
m_fragmentTransaction.replace(R.id.dl_flContainer, m_fragOne , FragmentOne.class.getSimpleName());
m_fragmentTransaction.addToBackStack(FragmentOne.class.getSimpleName());
m_fragmentTransaction.commit();

Prevent the same Fragment to be added multiple times in popBackStack

My activity is composed of 3 nested Fragments. There is my MainFragment that is displayed by default, ProductFragment that can be called from it, then DetailFragment can be called from ProductFragment.
I can go back and forth between my ProductFragment and DetailFragment. By doing so, the popStackBack method is accumulating similar fragments. Then, if I click on the back button, It will go back through all the Fragments as many time I called them.
What is the proper way to avoid the same Fragment to be kept in the back stack ?
EDIT :
I firstly call my main fragment :
if (savedInstanceState == null) {
getFragmentManager()
.beginTransaction()
.add(R.id.container, new SearchFragment(), "SEARCH_TAG")
.commit();
}
Here is the code that calls the fragments from the activity :
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.animator.enter_from_bottom, R.animator.exit_to_top, R.animator.enter_from_bottom, R.animator.exit_to_top);
ft.replace(R.id.container, new FactFragment(), "FACT_TAG");
ft.addToBackStack("FACT_TAG");
ft.commit();
Then, on back click :
#Override
public void onBackPressed() {
getFragmentManager().popBackStack();
}
I tried to get the tag of my current fragment and execute some specific code related to it but it doesn't work well. I also tried to addToBackStack() only when current Fragment wasn't already added to the backStack but it messed up my fragment view.
Use fragment's method isAdded() to evaluate the insertion. For example:
if(!frag.isAdded()){
//do fragment transaction and add frag
}
Here is my solution. Maybe dirty but it works. I implemented a method that returns the tag of the fragment that is displayed before clicking the on back button :
public String getActiveFragment() {
if (getFragmentManager().getBackStackEntryCount() == 0) {
return null;
}
String tag = getFragmentManager()
.getBackStackEntryAt(getFragmentManager()
.getBackStackEntryCount() - 1)
.getName();
return tag;
}
Then, on my onBackPressed() method :
// Get current Fragment tag
String currentFrag = getActiveFragment();
if(currentFrag.equals("PRODUCT_TAG")) {
// New transaction to first Fragment
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.animator.enter_from_right, R.animator.exit_to_left, R.animator.enter_from_right, R.animator.exit_to_left);
ft.replace(R.id.container, new SearchFragment(), "MAIN_TAG");
ft.commit();
} else {
// Go to Fragment-1
getFragmentManager().popBackStack();
}
Here is my handy and simple solution to check for duplicate insertion through fragment manager
at first, I check if it is first time intention for adding fragment and then I check if the fragment is presented using fragment manager
Fragment fragment = getSupportFragmentManager().findFragmentByTag("firstFragment");
if (fragment == null) {
getSupportFragmentManager().beginTransaction().add(R.id.frameLayout, new FirstFragment(), "firstFragment")
.addToBackStack(null)
.commit();
}else if(!fragment.isAdded()){
getSupportFragmentManager().beginTransaction().add(R.id.frameLayout, new FirstFragment(), "firstFragment")
.addToBackStack(null)
.commit();
}
Here is my solution:
Fragment curFragment = fragmentManager.findFragmentById(R.id.frameLayout);
if(curFragment != null
&& curFragment.getClass().equals(fragment.getClass())) return;
// add the fragment to BackStack here
Xamarin.Android (C#) version:
var curFragment = fragmentManager.FindFragmentById(Resource.Id.frameLayout);
if (curFragment != null
&& curFragment.GetType().Name == fragment.GetType().Name) return;
// add the fragment to BackStack here

Categories

Resources