Saving Fragment State on Orientation Change

James Jun picture James Jun · Dec 21, 2012 · Viewed 18.4k times · Source

I'm creating a file manager app for Android, and two classes below are the majority of the logic that goes into doing that. What I'm doing is that on startup of the ContentList, it adds the ContentListFragment to the container layout in the ContestList xml. By adding the ContentListFragment, I get the current path, then call setFileDir(String S) that basically gets the File at the passed in path, getting the list of Files at that location, initializing the array, and then initializing the adapter. I then set the Adapter, set the Action Bar UI, and the contextual Action Bar. Now, each time a item on the ContentListFragment is pressed, it creates another ContentListFragment, using the path of the selected item. The fragment before is then added to the back stack. Now that's all fine and dandy, the problem comes though when orientation occurs.

That setRetainInstance(true) in the onCreate of ContentListFragment is the only thing thats keeping the whole app from force closing when the app changes orientation. However, doing it this way cause the app to force close later when I return to it after a while (which is the main problem I'm having, and can't understand why).

I tried to replace the current ContentListFragment with a new one when the Activity is recreated on orientation change (code for this is not below), but the app force closes also with a NullPointerException at setFileDir(), and therefore everything else falls apart.

How do I save the fragment state so that on orientation change everything stays the same as it did before the orientation change, and without it force closing later when I return to it after a while?

Just in case, my app is just one Activity with recursive ContentListFragments.

public class ContentList extends DrawerActivity implements ContentListFragment.listFragmentListener{

    // instance variables
    private FragmentManager fm;
    private FragmentTransaction ft;
    private String currentPath;

    // Initializes variables.
    // If Activity is started for the first time, a path to the storage is
    // received.
    // Else, if it's an orientation change, the path is just retained.
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_list);

        if (savedInstanceState == null) {
            fm = getSupportFragmentManager();
            ft = fm.beginTransaction();
            File file = Environment.getExternalStorageDirectory();
            currentPath = file.getPath();
            ft.add(R.id.content_container_fragment_listview, new ContentListFragment());
            ft.commit();
        } else {
            fm = getSupportFragmentManager();
            currentPath = savedInstanceState.getString("PATH");
        }
    }

    // Grabs the currentPath in case of orientation changes.
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("PATH", currentPath);
    }

dfsas

public class ContentListFragment extends SherlockListFragment {

    // instance variables
    private ArrayList<Item> items;
    private ArrayList<Item> copy_move_queue_items;
    private ItemAdapter adapter;
    private listFragmentListener lfListener;
    private String currentPath;
    private MenuItem menuItemRename;

    // instantiates variables using setFileDir() and the path from the container Activity.
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        currentPath = ((ContentList) getActivity()).getCurrentPath();
        setFileDir(currentPath);

    }

    // Gets a reference to Activity interface
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            lfListener = (listFragmentListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + "must implement listFragmentListener");
        }
    }

    // Sets the UI of the listView and the ActionBar
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View v = inflater.inflate(R.layout.content_list_fragment, container, false);

        File file = Environment.getExternalStorageDirectory();
        String rootPath = file.getPath();

        // Sets Action Bar title to current directory, and creates an Up
        // affordance if the root path doesn't equal the current Path
        getSherlockActivity().getSupportActionBar().setTitle(null);
        getSherlockActivity().getSupportActionBar().setLogo(R.drawable.ab_icon);

        if (currentPath.equals(rootPath)) {
            getSherlockActivity().getSupportActionBar()
                    .setDisplayHomeAsUpEnabled(false);
            getSherlockActivity().getSupportActionBar()
                    .setHomeButtonEnabled(false);
        } else {
            getSherlockActivity().getSupportActionBar()
                    .setDisplayHomeAsUpEnabled(true);



            // getSherlockActivity().getSupportActionBar().setTitle("/" +
            // (currentPath.substring(currentPath.lastIndexOf("/") +1)));
        }

        return v;

    }

    // Sets the long click Contextual Action Mode to the ListView
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setActionMode();
        setListAdapter(adapter);
    }
    // Gets the list of files at the path and adds them to the Item ArrayList,
// initializing the adapter as well
public void setFileDir(String path) {
    File file = new File(path);
    File[] files = file.listFiles();
    Arrays.sort(files, new fileComparator());
    items = new ArrayList<Item>();
    for (File f : files) {
        items.add(new Item(f));
    }
    adapter = new ItemAdapter(getActivity(), R.layout.content_list_item, items);
}

Answer

Vivek Pratap Singh picture Vivek Pratap Singh · Jan 14, 2016

this worked for me

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        onCreate(savedInstanceState);
    }

and in manifest file inside your Activity tag

android:configChanges="orientation|screenSize"