How to maintain fragment state without backstack in tab? - android

I am trying to save fragment state in onSaveInstanceState but when i go back to fragment, it always reloaded again instead of starting from last state.
I looked into onCreateView and onActivityCreated and it always have onSaveInstanceState as null.
public void navigateFragment(String tag, Fragment fragment,
boolean shouldAdd) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
if (shouldAdd)
mStacks.get(tag).push(fragment); // push fragment on stack
ft.replace(android.R.id.tabcontent, fragment);
if (shouldAdd)
ft.addToBackStack(tag);
ft.commit();
}
As i am unable to use backstack because in tabs back stack is not useful. Any help would be highly appreciated.

In this case you have to manage fragments' states by yourself. I don't know exactly how your code works so the only thing I can do is to give you some hints.
The first thing you need to implement is saving fragment's state. Let's assume that all fragments have unique ids. In this case you need to create a map that will keep all the states:
private final Map<String, Fragment.SavedState> mFragmentStates = new HashMap<>();
private void saveFragmentState(String id, Fragment fragment) {
Fragment.SavedState fragmentState =
getSupportFragmentManager().saveFragmentInstanceState(fragment);
mFragmentStates.put(id, fragmentState);
}
You need to call this method for a fragment that you're going to remove. Then we need to restore fragment's state and that's how we can do it:
private void restoreFragmentState(String id, Fragment fragment) {
Fragment.SavedState fragmentState = mFragmentStates.remove(id);
if (fragmentState != null) {
fragment.setInitialSavedState(savedState);
}
}
This method you need to call before adding a fragment to a transaction.
The code provided should work fine but to make it work correctly on activity recreation we need to save and restore mFragmentStates properly:
private static final String KEY_FRAGMENT_STATES = "fragment_states";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* Your code ... */
if (savedInstanceState != null) {
Bundle fragmentStates =
savedInstanceState.getParcelable(KEY_FRAGMENT_STATES);
if (fragmentStates != null) {
for (String id : fragmentStates.keySet()) {
Fragment.SavedState fragmentState =
fragmentStates.getParcelable(id);
mFragmentStates.put(id, fragmentState);
}
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
/* Your code ... */
Bundle fragmentStates = new Bundle(mFragmentStates.size());
for (Map.Entry<String, Fragment.SavedState> entry : mFragmentStates.entrySet()) {
fragmentStates.put(entry.getKey(), entry.getValue());
}
outState.putParcelable(KEY_FRAGMENT_STATES, fragmentStates);
}
Also you can take a look at FragmentStatePagerAdapter class. It uses the same approach for managing states of ViewPager's fragments.
UPDATE: And so your code should end up looking something like this:
private Fragment mCurrentFragment;
public void navigateFragment(String tag, Fragment fragment,
boolean shouldAdd) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
if (shouldAdd) {
mStacks.get(tag).push(fragment); // push fragment on stack
}
if (mCurrentFragment != null) {
saveFragmentState(mCurrentFragment.getClass().getName(), mCurrentFragment);
}
mCurrentFragment = fragment;
restoreFragmentState(fragment.getClass().getName(), fragment);
transaction.replace(android.R.id.tabcontent, fragment);
if (shouldAdd) {
// You shouldn't use back-stack when managing fragment states by yourself.
transaction.addToBackStack(tag);
}
transaction.commit();
}
In this example I use fragment's class name as an id so all the fragment must have different classes. But you can use any other unique value as an id. And another important thing I have to mention is that you shouldn't use back-stack when managing fragment states by yourself. Back-stack performs similar state management and you will likely have conflicts.

I think you should use the idea of Shared Preferences, this is faster than using local files or database, and definitely easier to code. A good Android webpage # Storage Options. I'll put some sample code from the webpage and change a few to fit your needs.
First, get the data saved from preferences in onCreate() override method:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean silent = settings.getBoolean("silentMode", false);
...
}
Next let's save data before the fragment stops or exits, for various reasons. Achieve this by override onDetach method, the webpage override onStop() instead.
#Override
public void onDetach() {
super.onDetach();
...
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("silentMode", mSilentMode);
// Commit the edits!
editor.commit();
}
Good luck, have fun!

You are doing replace fragment, thats why fragment is getting destroyed. You can try below. Here i am doing two things in single FragmentTransaction, i am adding a new fragment & hiding the existing fragment.
Lets say we are adding fragment B on top of Fragment A
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(android.R.id.tabcontent, fragmentB, tagFragmentB)
.hide(fragmentManager.findFragmentByTag(tagFragmentA))
.addToBackStack(tag)
.commit();
Once you do back press, it will remove the fragment B & show the fragment A with same state(before you added fragment B)
Please note here tagFragmentA & tagFragmentB are tags with which fragments A & B are added respectively

clearBackStackEntry();
rl.setVisibility(View.GONE);
getSupportFragmentManager().beginTransaction()
.replace(FRAGMENT_CONTAINER, new HomeScreen())
.addToBackStack(null).commit();
private void clearBackStackEntry() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count > 0) {
getSupportFragmentManager().popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
TRY THIS AND One more for fragment also try this: but use support.v4.app.Fragment, May be it will help you
Fragment fr = new main();
android.support.v4.app.FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fr);
fragmentTransaction.commit();
// getActivity().finish();

declare
setRetainInstance(true)
In your fragment onCreate(). to recreate previous state
And link will helpful for understanding for how setRetainInstance work.
Understanding Fragment's setRetainInstance(boolean)
Why use Fragment#setRetainInstance(boolean)?
Thanks :)

it is very simple to handle these things. I can give you the sample to handle the back press on Fr agents which we added.
I have declared a fragment stack and push all the fragments in it like;
public static Stack<Fragment> fragmentStack;
make a method like this:
public static void replaceFragementsClick(Fragment fragementObj, Bundle bundleObj, String title){
try {
FragmentManager fragmentManager = ((FragmentActivity) mContext).getSupportFragmentManager();
if (fragementObj != null) {
fragementObj.setArguments(bundleObj);
fragmentManager.beginTransaction().replace(R.id.frame_container, fragementObj).commit();
}
DashBoardActivity.fragmentStack.push(fragementObj);
} catch (Exception e) {
e.printStackTrace();
}
}
Try this one also:
public static void replaceFragementsClickBack(Fragment fragementObj, Bundle bundleObj, String title){
try {
FragmentManager fragmentManager = ((FragmentActivity) mContext).getSupportFragmentManager();
if (fragementObj != null) {
fragementObj.setArguments(bundleObj);
fragmentManager.beginTransaction().replace(R.id.frame_container, fragementObj).commit();
DashBoardActivity.fragmentStack.pop();
}
} catch (Exception e) {
e.printStackTrace();
}
}
In the base activity where you have added, override the backpressed like:
#Override
public void onBackPressed() {
/**
* Do Current Fragment Pop
* */
fragmentStack.pop();
if(fragmentStack.size() >0){
Bundle bunldeObj = new Bundle();
//******Exit from Current Fragment
Fragment fragment = fragmentStack.pop();
// fragmentStack.push(fragment);
if(fragment instanceof PhotosFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Photos");
}else if(fragment instanceof PhotoDetatilFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Photos");
}else if(fragment instanceof PhotoFullViewFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Photos");
}else if(fragment instanceof HomeFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Home");
}else if(fragment instanceof VideosFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Videos");
}else if(fragment instanceof VideoDetailFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Videos");
}else if(fragment instanceof VideoViewFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Videos");
}else if(fragment instanceof MusicFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Music");
}else if(fragment instanceof MusicListFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Music");
}else if(fragment instanceof InstallAppsFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Apps");
}else if(fragment instanceof MessageFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Messages");
}else if(fragment instanceof MessageDetailFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Messages");
}else if(fragment instanceof LocateDeviceFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Locate Device");
}else if(fragment instanceof FilesFragmentBottomBar){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Files");
}else if(fragment instanceof AppsFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Apps");
}else {
super.onBackPressed();
Intent intent = new Intent(DashBoardActivity.this,ConnectDeviceActivity.class);
startActivity(intent);
finish();
}
}

I am not clear of way kind of vie you are using for implementing Tabs.
I guessed from,
ft.replace(android.R.id.tabcontent, fragment);
that you might have implemented FragmentTabHost.
write a customFragmentTabhost and override
#Override
public void onTabChanged(String tabId) {
FragmentTransaction t = getSupportFragmentManager().beginTransaction();
if (tabId.equals(“Tab1”)) {
TabFragment1 fragment1 = null;
if (getSupportFragmentManager().findFragmentByTag(“Tab1”) == null) {
fragment1 = new TabFragment1();
} else {
fragment1 = (TabFragment1) getSupportFragmentManager().findFragmentByTag("Tab1");
}
t.replace(R.id.realContent, fragment1, "Tab1").addToBackStack(null).commit();
}
}
UPDATE:
Ensure Activity is not recreated on orientation, If so setRetainInstance(true), so that even if activity is recreated on orientation change, the fragments will be retained.
Do give id for any views in the fragment. It is important for Android system to maintain state.

Related

onBackPressed with fragments and saving fragment state

I want to save fragment state so I use fragment .add() and fragment .show() methods.
the part I use to add fragments in my mainActivity is
android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.main_content, fragment, CURRENT_TAG);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
On back pressed in the fragment and getting back to it the get fragment by tag returns null
if (getSupportFragmentManager().findFragmentByTag(CURRENT_TAG) != null) {
drawerLayout.closeDrawers();
Runnable mPendingRunnable = new Runnable() {
#Override
public void run() {
android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
hideTransactions(CURRENT_TAG);
fragmentTransaction.show(getSupportFragmentManager().findFragmentByTag(CURRENT_TAG)).commit();
}
};
although onBackPressed the state of the fragment is right(TAG_PREV returns not null) in the on back pressed method
#Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawers();
return;
}
if (CURRENT_TAG == TAG_HOME) {
return;
}
navItemIndex = 0;
TAG_PREV = CURRENT_TAG;
CURRENT_TAG = TAG_HOME;
loadHomeFragment();
super.onBackPressed();
}
addToBackStack saves the transaction, in this case: fragmentTransaction.add(R.id.main_content, fragment, CURRENT_TAG); and when you press back(onBackPressed) you are reversing that transaction. So that will imply you are removing the previously added fragment.
It is not possible to maintain entire fragment in back stack, There is no provision given by android teams.
You have to use onSaveInstanceState for saving current state/data when you are leaving fragment.
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
Log.i(TAG, " onSaveInstanceState.");
savedInstanceState.putString("greeting", "Hello");
}
After that when again coming on that fragment you have to use.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String greeting = (savedInstanceState != null) ? savedInstanceState.getString("greeting") : "null";
Log.i(TAG, " onCreate: " + greeting);
}
Please let me if it dosen't work for you.

Previous fragment visible behind current one after screen rotation

In my main activity I am displaying several fragments depending on option chosen by the user. When screen is rotated and then fragment changed, the previous fragment, one that was visible while rotating screen, is transparent and still visible behind or over new one. I am adding fragments using add() method and then removing old ones with remove(). I am aware that simply using replace() would fix my problem but my main fragment contains many network and database calls on create and I would like to remember its state rather than make many unnecessary calls.
Why does my problem even occur when I am removing fragments other than the main one? How can I fix it?
Here is how I am setting my fragments:
public void setFragment(FragmentEnum fragmentEnum, #Nullable Bundle bundle) {
Fragment oldFragment = getCurrentFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
currentFragment = fragmentEnum;
mMapFragment = (MainMapFragment) fragmentManager.findFragmentByTag(MainMapFragment.TAG);
if (mMapFragment == null) {
mMapFragment = MainMapFragment.newInstance(bundle);
}
if (fragmentEnum == FragmentEnum.MAP) {
if (!mMapFragment.isAdded()) {
ft.add(R.id.container_contents, mMapFragment, MainMapFragment.TAG);
}
if (oldFragment != null && !(oldFragment instanceof MainMapFragment)) {
ft.remove(oldFragment);
}
ft.show(mMapFragment);
if (mNavigationDrawerFragment != null) mNavigationDrawerFragment.unselectItems();
} else {
ft.hide(mMapFragment);
Fragment newFragment = null;
String tag = null;
switch (fragmentEnum) {
case LIST:
newFragment = MainListFragment.newInstance();
tag = MainListFragment.TAG;
break;
case FAVORITE:
newFragment = MainFavoriteFragment.newInstance();
tag = MainFavoriteFragment.TAG;
break;
case ADD:
newFragment = MainAddFragment.newInstance();
tag = MainAddFragment.TAG;
break;
case USER:
newFragment = MainUserFragment.newInstance();
tag = MainUserFragment.TAG;
break;
}
ft.add(R.id.container_contents, newFragment, tag);
if (oldFragment != null && !(oldFragment instanceof MainMapFragment)) {
ft.remove(oldFragment);
}
ft.show(newFragment);
}
ft.commit();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(SAVE_STATE_CURR_FRG, currentFragment);
}
onCreate(){
...
if (savedInstanceState != null) {
FragmentEnum savedFragmentEnum = (FragmentEnum) savedInstanceState.getSerializable(SAVE_STATE_CURR_FRG);
setFragment(savedFragmentEnum, null);
}
...
}

How to check if the fragment exists

I am trying to talk to the fragments from activity.
Here in my MainActivity I am adding multiple fragments ok so for fine.
My main requirement is I don't want to add if fragment is already added.
So how can we check this condition?
Please help me some one.
code:-
private void intializingFragments(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
private View.OnClickListener intialization() {
return new View.OnClickListener() {
#Override
public void onClick(View v) {
int getId = v.getId();
if (getId == R.id.first) {
intializingFragments(new Fragment1());
} else if (getId == R.id.second) {
intializingFragments(new Fragment2());
} else if (getId == R.id.third) {
intializingFragments(new Fragment3());
}
}
};
}
You can use findFragmentByTag() or findFragmentById() functions to get a fragment. If mentioned methods are returning null then that fragment does not exist.
Fragment fragmentA = fragmentManager.findFragmentByTag("frag1");
if (fragmentA == null) {
// not exist
} else {
// fragment exist
}
for example:- http://wiki.workassis.com/android-load-two-fragments-in-one-framelayout/
You may find fragment in fragmentmanager:
List<Fragment> frags = getSupportFragmentManager().getFragments();
for (Fragment f : frags) {
<find what you want>...
}
Or you may add fragment with tag:
getSupportFragmentManager()
.beginTransaction()
.add(R.id.frame, new MyFragment(), "frag1")
.commit();
And find by tag
getSupportFragmentManager().findFragmentByTag("frag1");
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
Fragment topFragment = fragmentManager.findFragmentById(R.id.container);
FragmentA fragmentA = new FragmentA();
if(topFragment!= null)
{
transaction.remove(topFragment);
transaction.add(R.id.container, fragmentA, "FA");
transaction.commit();
}
else
{
transaction.add(R.id.container, fragmentA, "FA");
transaction.commit();
}
try this
private void intializingFragments(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment topFragment = fragmentManager.findFragmentById(R.id.container);
if(topFragment!= null)
{
fragmentTransaction.remove(topFragment);
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
else
{
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
How to check whether a fragment exists, without knowing its resource ID or tag:
// MyActivity.kt
val exists: Boolean = supportFragmentManager
.fragments
.filterIsInstance<MyFragment>()
.isNotEmpty()
There are many ways by which you can track the last added fragment. The simplest one is by finding the tag within fragment manager. Here is the sample code of it:
public boolean isFragmentPresent(String tag) {
Fragment frag = getSupportFragmentManager().findFragmentByTag(tag);
if (frag instanceof HomeFragment) {
return true;
} else
return false;
}
Alternatively, you can use your own variable to check whether the last added fragment is the same as the current fragment. Here is the sample code for it:
public boolean isCurrentFragment(Fragment fragment) {
if (fragment instanceof HomeFragment && getLastAddedFragment() instanceof HomeFragment) { // getLastAddedFragment() is a method which return the last added fragment instance
return true;
} else
return false;
}
And you can use it like:
if (isCurrentFragment(new HomeFragment())) {
// Last added Fragment is the HomeFragment
}
You can go for popBackStack Pop the last fragment transition from the manager's fragment back stack. If there is nothing to pop, false is returned. enter link description here
You can get the list of previously added fragments from the fragment manager. Then just check whether the list contains your fragment object or not.
getSupportFragmentManager().getFragments().contains(yourFragment);
This one doesn't work
!getSupportFragmentManager().getFragments().contains(fragment)
This works for me
getSupportFragmentManager().findFragmentByTag(fragment::class.java.getSimpleName()) == null

Handle Fragment On Screen Orientation Changes?

I am useing This Sort of Code To Handle Three Fragment in Main Activity ...
FragmentA is Fixed it One Frame .. I change FragmentB and FragmentC on Button Click on FragmentA.
his Code is Running well either in Portrait or Landscape view .Here is The Code bellow.
public class MainActivity extends FragmentActivity implements
OnSwitchClickListener {
FragmentManager manager;
FragmentA fragA;
FragmentB fragB;
FragmentC fragC;
boolean fragBSet = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragA = new FragmentA();
fragB = new FragmentB();
fragC = new FragmentC();
manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.add(R.id.a_container, fragA, "frag A");
if (fragBSet) {
ft.add(R.id.bc_container, fragC, "frag C");
} else {
ft.add(R.id.bc_container, fragB, "frag B");
}
fragBSet = true;
ft.commit();
}
#Override
public void onSwitchClick(View v) {
Toast.makeText(getApplicationContext(), "Switch clkick from Activity",
Toast.LENGTH_LONG).show();
FragmentTransaction ft = manager.beginTransaction();
if (fragBSet) {
ft.remove(fragB);
ft.add(R.id.bc_container, fragC, "frag C");
fragBSet = false;
} else {
ft.remove(fragC);
ft.add(R.id.bc_container, fragB, "frag B");
fragBSet = true;
}
ft.commit();
}
This Code is Running well either in Portrait or Landscape view ... But When Ever I change the Orientation The Two Fragments Override One Another.
Need Solution.
When your orientation change, your Activity is recreated.
"In the scenario where a user rotates their device, Android will destroy your
application’s activity(s). Before destroying them it calls, onSaveInstanceState,
allowing developers to persist data. Once the activity is recreated post
rotation, the OS will call onRestoreInstanceState giving developers a chance to
restore the application state pre-rotation."
You should try to save your Fragments State.
putFragment: Put a reference to a fragment in a Bundle. This Bundle can be persisted as saved state, and when later restoring getFragment(Bundle, String) will return the current instance of the same fragment.
#Override
protected void onSaveInstanceState(Bundle outState) {
FragmentManager manager = getFragmentManager();
manager.putFragment(outState, MyFragment.TAG, mMyFragment);
}
getFragment: Retrieve the current Fragment instance for a reference previously placed with putFragment(Bundle, String, Fragment).
private void instantiateFragments(Bundle inState) {
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
if (inState != null) {
mMyFragment = (MyFragment) manager.getFragment(inState, MyFragment.TAG);
} else {
mMyFragment = new MyFragment();
transaction.add(R.id.fragment, mMyFragment, MyFragment.TAG);
transaction.commit();
}
}
restoreFragment:
#Override
protected void onRestoreInstanceState(Bundle inState) {
instantiateFragments(inState);
}
Hope this helps.

How to make a fragment be in the exact same way I left it when I return to it from another fragment?

I have a few fragments in my app, but my code opens a new fragment every time I click the button.
I want to know how can I change this, and make the fragment return to the exact same state I left it in.
The code im using right now:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragments);
MainActivity fragment = new MainActivity();
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.add(R.id.fragment_place, fragment);
transaction.commit();
turnGPSOn();
}
public void onSelectFragment(View view) {
if (view == findViewById(R.id.add))
{
newFragment = new Add();
}
else if (view == findViewById(R.id.map))
{
newFragment = new MainActivity();
}
else
{
newFragment = new Add();
}
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.fragment_place, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
Thanks!
You are getting a new fragment each time because you are calling to new XXX() each time.
I think you could use findFragmentByTag in order to solve this problem. As you can see here the replace function can accept a third parameter that is a String, this String can be used as an id to identify different fragments you have used previously.
So to sum up you can:
Call Fragment f = getSupportFragmentManager().findFragmentByTag("FragAdd"); for example in order to retrieve the first fragment.
If f is null, that means that you haven't used that fragment yet, so you have to call to new Add() if not, use that fragment to replace the old one. For example like this:
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.fragment_place, newFragment, "FragAdd"); //or whatever other string you want to use
transaction.addToBackStack(null);
transaction.commit();
Hope it helps :)
I faced this issue a time ago, and managed to solve it for applications with one visible fragment at a time; for activities with several visible fragments, you'll need to make some adjustments. This is what I did.-
Create a custom ParentActivity, so that all my activities extend it. ParentActivity knows about which is the current Fragment that is showed, and how to show a new one.
public String currentFragmentTag;
public ParentFragment getCurrentFragment(int fragmentWrapperResId) {
ParentFragment res = null;
FragmentManager fragmentManager = getSupportFragmentManager();
res = (ParentFragment) fragmentManager.findFragmentById(fragmentWrapperResId);
if (res != null && res.isHidden()) {
if (currentFragmentTag != null) {
res = (ParentFragment) fragmentManager.findFragmentByTag(currentFragmentTag);
}
}
return res;
}
public void openFragment(ParentFragment fragment, int fragmentWrapperResId, int enterAnim, int exitAnim, int popEnterAnim, int popExitAnim, boolean addToBackStack) {
FragmentManager fragmentManager = getSupportFragmentManager();
ParentFragment currentFragment = getCurrentFragment(fragmentWrapperResId);
if (currentFragment != null && currentFragment.getTagName().equals(fragment.getTagName())) {
return;
}
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);
if (currentFragment != null) {
transaction.hide(currentFragment);
}
if (fragment.isAdded()) {
transaction.show(fragment);
} else {
transaction.add(fragmentWrapperResId, fragment, fragment.getTagName()).setBreadCrumbShortTitle(fragment.getTagName());
}
if (addToBackStack) {
transaction.addToBackStack(fragment.getTagName());
} else {
currentFragmentTag = fragment.getTagName();
}
transaction.commit();
}
Create a ParentFragment, to be extended by the rest of Fragments, with a tag getter
public String getTagName() {
return getClass().getSimpleName() + System.identityHashCode(this);
}
As you can see, the main idea is not replacing visible fragments, but just adding them and show/hide whenever it's needed. This way, the fragments will keep their states, as they're not destroyed until you remove them from the bakstack.

Categories

Resources