Save and restore instance of Fragment with ViewPager (FragmentStatePagerAdapter) - android

Short version:
I have activity with fragment, which include ViewPager (with FragmentStatePagerAdapter) and on resume to this fragment it recreates. How can I by back press return to Fragment and restore is state and it's Viewpager?
Details:
I have an activity with FrameLayout (R.id.themesFragmentsLayout), in activity's method onCreate(..) I do:
if (savedInstanceState == null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ThemesFragment fragment = new ThemesFragment();
fragmentTransaction.replace(R.id.themesFragmentsLayout, fragment, ThemesFragment.TAG);
fragmentTransaction.commit();
}
ThemesFragment include only ViewPager with FragmentStatePagerAdapter, which holds 3 fragments:
public Fragment getItem(int position) {
switch (position) {
case ID_THEME_PAST:
return new ThemePastFragment();
case ID_THEME_OF_DAY:
return new ThemeOfDayFragment();
case ID_THEME_UPCOMING:
return new ThemeUpcomingFragment();
default:
return null;
}
}
In ThemeOfDayFragment for example, user can click some button and I change ThemesFragment (which holds ViewPager) with some another (for example ThemeDetails):
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
fragmentTransaction.addToBackStack(newFragment.getClass().getSimpleName());
fragmentTransaction.replace(((AboutMyStyleApplication) getActivity().getApplication()).getCurrentFragmentsLayoutId(), newFragment, newFragment.getClass().getSimpleName());
fragmentTransaction.commitAllowingStateLoss(); // or fragmentTransaction.commit(); - same result
But when he came back (by back key press for example) ThemesFragment recreates, and all fragments in ViewPager recreates to.
In ThemesFragment I set setRetainInstance(true)
Can anyone help?

Related

Fragment not showing previous data when coming from another fragment

In my android activity I am using multiple fragments, I am successfully switching these fragments according to my requirement but problem is that when I am switching Fragment 1 to Fragment 2 and back from Fragment 2 to Fragment 1, Fragment 1 not showing previous data Fragment 1 start from stretch, but I want to show previous data same as I was selected.
Here is my code for go Fragment 1 (fragment_search_customerProfile) to Fragment 2 (fragment_CustomerInfo):
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.filterFram, new fragment_Search());
FrameLayout layout = (FrameLayout) rootView.findViewById(R.id.cpFrame);
layout.removeAllViewsInLayout();
transaction.remove(new fragment_search_customerProfile()).commit();
Here is my code for back Fragment 1 (fragment_search_customerProfile) fromFragment 2 (fragment_CustomerInfo):
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
Log.d("fragment_Search", fromSearch + "");
transaction.replace(R.id.custIndoFram, new fragment_search_customerProfile());
FrameLayout layout = (FrameLayout) rootView.findViewById(R.id.custIndoFram);
layout.removeAllViewsInLayout();
transaction.remove(new fragment_CustomerInfo()).commit();
Can anyone explain me how can I stay save my fragment data?
Instead of transaction.replace(R.id.filterFram, new fragment_Search());
you can use transaction.add to add fragment while having the data of first one
transaction.add(R.id.filterFram, new fragment_Search());
transaction.addToBackStack(null);
From fragment two you can use .show instead of replace to show the first fragment
and hide fragment two from the first one. transaction.show(getSupportFragmentManager().findFragmentByTag("firstFragmentTag")).commit();
You can simple keep the instances of the fragments, so in your Activity you would have fields like that.
private Fragment fragment1;
private Fragment fragment2;
And now you can use the sexy replace() option,
To add Fragment1
if (fragment1 == null) {
fragment1 = new fragment_Search();
}
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.filterFram, fragment1);
and same for Fragment2
And you can hold the state of the fragment (data it retrieves) in the Fragment itself, and in your onViewCreated() you check, if the state is not null, you update the view immediately.
class Fragment1 extends Fragment {
private State state;
public void onViewCreated(View v) {
if (state != null) {
// Update UI here
}
}
}
UPDATE
Using your own code
private Fragment fragment1; // This is a field outside of below method
if (fragment1 == null) {
fragment1 = new fragment_Search();
}
FragmentManager manager = getChildFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.filterFram, fragment1).commit();
FrameLayout layout = (FrameLayout) rootView.findViewById(R.id.cpFrame);
layout.removeAllViewsInLayout();
Going to fragment2 should be the same, and this code is used to go to Fragment1 and Fragment2, doesn't matter if you are going back or first time.
You have to add fragment instead of remove or replace

Common way to switch fragments without loosing state

I am pretty new to android development so I am curious how to work properly with Fragments.
My application contains a BottomNavigationActivity which switches between 3 fragments with this code:
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_montage_order_detail, fragment).commit();
I am storing the Fragments in a List<Fragment> to avoid loosing the current state. But everytime I replace the fragment with another the method onDestroy() is called.
I know, I know I could add and remove the fragment in the fragmentmanager instead of replacing it. I googled alot and most of the tutorials tell me to replace the fragment.
Whats the common way to keep a fragments state without recreating it on every call?
Find the solution
It will not recreate fragment anytime
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().add(R.id.content_montage_order_detail, fragment).commit();
Use fragment TAG at time of creation of fragment then when you want to get it again use findFragmentByTag. if fragment already created then old one will be find by fragment manager.
Fragment previousFragment = fragmentManager.findFragmentByTag("TAG");
I suggest you use show,not forreplace
protected void addFragmentStack(Fragment fragment) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (this.mContent != fragment) {
if (fragment.isAdded()) {
ft.hide(this.mContent).show(fragment);
} else {
ft.hide(this.mContent).add(getFragmentViewId(), fragment);
}
this.mContent = fragment;
}
ft.commit();
}
Try using switchFragment to switch fragment, it will show fragment if it is already added.
Use fragmentTransaction.show method to re-use existing fragment i.e. saved instance.
public void switchFragment (Fragment oldFragment, Fragment newFragment, int frameId) {
boolean addFragment = true;
FragmentManager fragmentManager = getFragmentManager ();
String tag = newFragment.getArguments ().getString (BaseFragment.TAG);
Fragment fragment = fragmentManager.findFragmentByTag (tag);
// Check if fragment is already added
if (fragment != null && fragment.isAdded ()) {
addFragment = false;
}
// Hide previous fragment
String oldFragmentTag = oldFragment.getArguments ().getString (BaseFragment.TAG);
if (!tag.equals (oldFragmentTag)) {
FragmentTransaction hideTransaction = fragmentManager.beginTransaction ();
Fragment fragment1 = fragmentManager.findFragmentByTag (oldFragmentTag);
hideTransaction.hide (fragment1);
hideTransaction.commit ();
}
// Add new fragment and show it
FragmentTransaction addTransaction = fragmentManager.beginTransaction ();
if (addFragment) {
addTransaction.add (frameId, newFragment, tag);
addTransaction.addToBackStack (tag);
}
else {
newFragment = fragmentManager.findFragmentByTag (tag);
}
addTransaction.show (newFragment);
addTransaction.commit ();
}
Ya, you can also manage the state by managing the backstack.

Issue in Fragments in android

When I click on the back icon in the layout then it goes to previous fragment but it doesn't go to the fragment it was killed. what is the solution for this?
I'm using finish() and backstack but it not works for me
back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
android.support.v4.app.Fragment onlineFragments = new OnlineFragments();
android.support.v4.app.FragmentManager fragmentManagerprofile = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentprofileTransaction = fragmentManagerprofile.beginTransaction();
fragmentprofileTransaction.replace(R.id.background_fragment, onlineFragments);
fragmentprofileTransaction.commit();
}
});
Fragment A
case R.id.recharge:
HomeActvity.toolbar.setVisibility(View.GONE);
android.support.v4.app.Fragment Recharge = new Prepaid_recharge();
android.support.v4.app.FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.containerView, Recharge);
fragmentTransaction.commit();
break;
Whenever your making Transactions between fragments and you want to navigate back to the previous fragment(s) (Back Button), in the transaction, you must add this transaction to the backStack before committing:
Android docs:
"Before you call commit(), however, you might want to call addToBackStack(), in order to add the transaction to a back stack of fragment transactions. This back stack is managed by the activity and allows the user to return to the previous fragment state, by pressing the Back button."
https://developer.android.com/guide/components/fragments.html#Transactions
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
I use this code to add and remove the fragment. In case I do not need that fragment to be in the back stack I send the boolean value as false. Doing this when pressing back button from toolbar It open the correct activity
public static void changeFragment (MyActivity activity, Fragment fragment, int fragmentContainer, boolean addToBackStack){
FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(fragmentContainer, fragment);
/*here we keep track of fragments and avoiding last blank fragment by passing true*/
if(addToBackStack){
fragmentTransaction.addToBackStack(null);
}
fragmentTransaction.commit();
}

Resume/bring to top active (but hidden) fragment

I have added 3 fragments to my Activity with
String name = "fragment1"; // and ..2 and ..3
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.content_frame, fragment, name);
fragmentTransaction.addToBackStack(name);
fragmentTransaction.commit();
The last added (third) Fragment now is visible on top.
Now I want to resume to the first added Fragment. But how?
I can find this Fragment with
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment firstFragment = fragmentManager.findFragmentByTag("fragment1");
If I call fragmentManager.getFragments() I still can find all three Fragments.
How to bring firstFragment back to top, make it visible again?
You can hide your 2nd and 3rd fragment and make your 1st fragment visible. So you'll have the effect that first fragment is shown on top and others are invisible.
solution:
Use the FragmentTransaction's show and hide method. Firs you need to find all the fragment and call the FragmentTransaction to show and hide 2nd and 3rd fragments.
Here's how I do it in my app when I want to switch to fragment:
FragmentTransaction transaction = getFragmentManager().beginTransaction();
if (fragment.isAdded())
{
transaction.show(fragment);
}
else
{
transaction.replace(R.id.container, fragment);
}
transaction.addToBackStack(null);
transaction.commit();
Note the use of show.
It ended up with this:
/**
* #param tag name of the fragment to resume and to bring to top
* #return true if fragment has been found
*/
private boolean bringFragmentToTop(String tag) {
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(tag);
if (fragment != null) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
for (Fragment f : fragmentManager.getFragments()) {
if (f == fragment)
fragmentTransaction.show(f);
else
fragmentTransaction.hide(f);
}
fragmentTransaction.commit();
return true;
}
return false;
}

Replace a Fragment created from Navigation Drawer with another dynamically

I have a navigation drawer that works well. By well I mean I can navigate through all the fragments tied to the Navigation drawer (A,B,C,D). My issue arises here. Lets say am in Fragment A, in this fragment I have a button which on clicking should ideally replace the fragment with another one say Frag Z, and once I am in Frag Z I can return back to frag A.
To achieve this I use the below code. However the new fragment Z appears transparent on top of Fragment A. What could be the problem:
Bundle bundle = new Bundle();
bundle.putInt("int", 1);
bundle.putString("str","string" );
fragmentTransaction = getFragmentManager().beginTransaction();
FragZ fragmentz = new FragZ();
fragment.setArguments(bundle);
fragmentTransaction.replace(R.id.some_container, fragmentz);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
EDIT:
I have found a workaround to this as shown below,however it does not completely solve my problem since the newly displayed fragment is still shown with the navigation drawer capable of being toggled,but it atleast removed the overlaying of the fragments. I would still want a solution to launching an independent fragment
Bundle bundle = new Bundle();
bundle.putInt("int", 1);
bundle.putString("str","string" );
FragZ fragmentz = new FragZ();
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
fragment.setArguments(bundle);
ft.replace(R.id.main, fragment);
ft.addToBackStack(null);
ft.commit();
Create a method in your activity to launch fragments. Whenever you want to display the fragment, just call in with a number or string to represent the fragment. You can use the same function to launch fragments from your navigation drawer.
For example:
public void displayView(int position) {
Fragment fragment = null;
currentFragmentNumber = position;
switch (position) {
case 0:
fragment = new frag1();
break;
case 1:
fragment = new frag2();
break;
case 2:
fragment = new frag3();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment)
.addToBackStack("tag").commit();
} else {
// error in creating fragment
Log.e(TAG, "Error in creating fragment");
}
}
You can call this function from your activity by using:
((**ActivityName**) getActivity()).displayView(0);

Categories

Resources