1

From all the searches I have found on SO stating that you should save your instance state in the @Override public void onSaveInstanceState(Bundle outState)

However This is tightly coupled with the activities lifestyle.

How can I save the state of my listview in a fragment that gets swapped out with another fragment. I have one main activity which all the fragments are loaded into.

I have tried this so far:

    @Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    //Save adapter data so that when the fragment is returned to it can be resused.
    ArrayList<CategoryMobileDto> categories = new ArrayList<CategoryMobileDto>();
    for(int i=0; i < adapter.getCount();i++)
    {
        categories.add(adapter.getItem(i));
    }
    String persistData = new Gson().toJson(categories);
    outState.putString("Categories", persistData);        
}

and then in my OnCreate();

   if(savedInstanceState!=null)
    {
        String data =savedInstanceState.getString("Categories");
        Type collectionType = new TypeToken<ArrayList<CategoryMobileDto>>() {
        }.getType();
        adapter.addAll(gson.<Collection<CategoryMobileDto>>fromJson(data, collectionType));
        adapter.notifyDataSetChanged();
    }else{
       // Make request to server
    }

however savedInstanceState is always null. But this makes sense as my activity is not being destroyed and recreated.

This is how I transition from one fragment to another:

    fragment.setArguments(args);
    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    fragmentTransaction.replace(R.id.container, fragment, "ProductListFragment");
    fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();

Is there a way i can save the state of my listview when the fragment is removed and then restore it again when the fragment is popped from the back-stack?

Zapnologica
  • 22,170
  • 44
  • 158
  • 253

2 Answers2

0

Move this code from onCreate() to onActivityCreated() of Fragment

if(savedInstanceState!=null)
    {
        String data =savedInstanceState.getString("Categories");
        Type collectionType = new TypeToken<ArrayList<CategoryMobileDto>>() {
        }.getType();
        adapter.addAll(gson.<Collection<CategoryMobileDto>>fromJson(data, collectionType));
        adapter.notifyDataSetChanged();
    }else{
       // Make request to server
    }

If you have any query please let me know.

droidd
  • 1,361
  • 10
  • 15
  • Does my activity get recreated every time I swap out a fragment? – Zapnologica Jan 23 '15 at 09:03
  • I recommend this solution for fragment. – droidd Jan 23 '15 at 09:05
  • Doesn't seem work for me. Saved instance is always null. And ` @Override public void onSaveInstanceState(Bundle outState) ` does not get called when swapping out the fragment for another? (only on screen rotate).Any thoughts. I cant somehow link it to the fragmentManager? – Zapnologica Jan 23 '15 at 09:34
0

You can use the Arguments with the Fragment(Only if you have the data to show in fragment before the fragment is loaded means attached). You can setArguments to a fragment which will be persisted when you go to another fragment by fragment transaction and when you come back, load the fragment from the getArguments function.

public void setArguments (Bundle args)

Added in API level 11 Supply the construction arguments for this fragment. This can only be called before the fragment has been attached to its activity; that is, you should call it immediately after constructing the fragment. The arguments supplied here will be retained across fragment destroy and creation.

public final Bundle getArguments ()

Added in API level 11 Return the arguments supplied when the fragment was instantiated, if any.

Please find the sample code below for passing data between fragments :

main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/flContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" >

</FrameLayout>

MainActivity.java

public class MainActivity extends Activity implements IFragContainer {

private static final String FRAG_TAG = "FragTag";
private FragBase mFrag;
private String dataToBePassedBack;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    changeFragment(FragA.class, "Data to Frag A");
}

@Override
public void changeFragment(Class<? extends FragBase> fragClass, String data) {
    try {
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        mFrag = fragClass.newInstance();
        Bundle args = new Bundle();
        args.putString("DATA", data);
        mFrag.setArguments(args);
        ft.replace(R.id.flContainer, mFrag, FRAG_TAG);
        ft.addToBackStack(mFrag.toString());
        ft.commit();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
public void onBackPressed() {
    dataToBePassedBack = mFrag.getDataToPassBack();
    FragmentManager mgr = getFragmentManager();
    mgr.executePendingTransactions();

    boolean doCheckAndExit = true;

    for (int i = mgr.getBackStackEntryCount() - 1; i > 0; i--) {
        BackStackEntry entry = mgr.getBackStackEntryAt(i);

        if (!TextUtils.isEmpty(entry.getName())) {
            mgr.popBackStackImmediate(entry.getId(),
                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
            doCheckAndExit = false;
            break;
        }
    }

    if (doCheckAndExit) {
        finish();
    } else {
        mFrag = (FragBase) mgr.findFragmentByTag(FRAG_TAG);
    }
}

@Override
public String getDataToBePassedBack() {
    return dataToBePassedBack;
}

}

IFragContainer.java

public interface IFragContainer {
void changeFragment(Class<? extends FragBase> fragClass, String data);

String getDataToBePassedBack();
}

FragBase.java

public abstract class FragBase extends Fragment {

public String getDataToPassBack(){
    return null;
}

}

FragA.java

public class FragA extends FragBase {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    Button btn = new Button(getActivity());
    final IFragContainer fragContainer = (IFragContainer) getActivity();
    if (TextUtils.isEmpty(fragContainer.getDataToBePassedBack())) {
        btn.setText(getArguments().getString("DATA"));
    } else {
        btn.setText(fragContainer.getDataToBePassedBack());
    }
    btn.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
            LayoutParams.WRAP_CONTENT));
    btn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            fragContainer.changeFragment(FragB.class, "Data to Frag B");
        }
    });
    return btn;
}

}

FragB.java

public class FragB extends FragBase {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    Button btn = new Button(getActivity());
    btn.setText(getArguments().getString("DATA"));
    btn.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
            LayoutParams.WRAP_CONTENT));
    btn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            getActivity().onBackPressed();
        }
    });
    return btn;
}

@Override
public String getDataToPassBack() {
    return "Data from Frag B to A";
}
}
Eldhose M Babu
  • 14,382
  • 8
  • 39
  • 44
  • So are you saying i should pass arguemtns from frag1 => frag2 and the pass them back when you pres the back button from frag2 => frag1 ? – Zapnologica Jan 23 '15 at 09:11
  • @Zapnologica No, if you need to pass some values to a fragment while creating it, you can use setArguments and inside fragment, you can use getArguments. So for passing some date from frag A to frag B, you can create the object of frag B and call setArguments on frag B object with the data to be passed. When you return, if you need some data to be given back, you need to take the help of your parent activity by interfacing it. Like, you have context (means your parent activity) in your B frag, set data to that cntext with an interface, then coming back to frag A, get the data from cntext in A. – Eldhose M Babu Jan 23 '15 at 09:22
  • I need frag a to save data and then send it back to frag A when frag A is poped off the stack into view again. I am not trying to transfer data between any two fragments. It should all revolve around a single fragments life cycle. – Zapnologica Jan 23 '15 at 09:27