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);
}
The first key is that we can save our Fragments' state ourselves using FragmentManager. saveInstanceState(Fragment) . Before removing the Fragment, call this method to get a Bundle containing your Fragment's saved state! The second key is restoring state.
Another most common solution to dealing with orientation changes by setting the android:configChanges flag on your Activity in AndroidManifest. xml. Using this attribute your Activities won't be recreated and all your views and data will still be there after orientation change.
Some device configurations can change during runtime (such as screen orientation, keyboard availability, and when the user enables multi-window mode). When such a change occurs, Android restarts the running Activity ( onDestroy() is called, followed by onCreate() ).
The savedInstanceState is a reference to a Bundle object that is passed into the onCreate method of every Android Activity. Activities have the ability, under special circumstances, to restore themselves to a previous state using the data stored in this bundle.
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"
use this for save state of fragment on orientation.
onCreate(Bundle save)
{
super.onCreate(save);
setRetainInstance(true);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With