Reputation: 3565
I am trying to restore the state of the action mode on orientation change. But it does not work properly. Following the below sequence of steps, in #3 and #4 the selections get corrupted :
myListView.getCheckedItemCount()
in onSaveInstanceState()
returns 0 on #3. That's where the problem starts.
What am i doing wrong in my fragment(using support library)?
@Override
public void onSaveInstanceState(Bundle outState) {
//check if any items are selected
if (myListView.getCheckedItemCount() > 0) {
//get the list of selected items and convert it to an int Array
//because SparseBooleanArray cannot be stored in a bundle
SparseBooleanArray selectedItems = myListView.getCheckedItemPositions();
int[] selectedItems_intArray = new int[myListView.getCheckedItemCount()];
for (int i = 0; i < selectedItems.size(); i++) {
if (selectedItems.valueAt(i) == false)
continue;
selectedItems_intArray[i] = selectedItems.keyAt(i);
}
outState.putIntArray(KEY_CHECKED_ITEMS, selectedItems_intArray);
}
}
@Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (savedInstanceState != null) {
int[] checkedItems = savedInstanceState.getIntArray(KEY_CHECKED_ITEMS);
if (checkedItems != null) {
actionMode = ((ActionBarActivity) getActivity()).startSupportActionMode(new ContextualActionBarActionModeCallBack());
for (int i = 0; i < checkedItems.length; i++) {
myListView.setItemChecked(checkedItems[i], true);
}
actionMode.setTitle(myListView.getCheckedItemCount() + " selected");
}
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
myListView = (ListView) getActivity().findViewById(R.id.myListView);
adpt = new myCustomCursorAdapter(getActivity());
myListView.setAdapter(adpt);
//Choice mode is allowed only after a long click
//disabling it on first time load
myListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
myListView.setOnItemLongClickListener(new OnItemLongClickListener(){
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id){
if(actionMode == null){
//Start the action mode
actionMode = ((ActionBarActivity)getActivity()).startSupportActionMode(new ContextualActionBarActionModeCallBack());
myLisVIew.setItemChecked(position, true);
actionMode.setTitle(myListView.getCheckedItemCount() + " selected");
return true;
}
else return false;
}
});
}
@Override
public void onResume(){
super.onResume();
getLoaderManager().initLoader(0,null,this);
}
private class ContextualActionBarActionModeCallBack implements ActionMode.Callback{
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.mycontextmenu, menu);
myListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
...
...
}
ListView layout element :
<ListView
android:id="@+id/myListView"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_alignParentTop="true"
android:listSelector="@android:color/transparent"
android:stackFromBottom="true"
android:layout_above="@id/layout_input"
android:divider="#00000000"
/>
Upvotes: 2
Views: 2443
Reputation: 3565
The issue is that the choice mode of the list view is being reset to a default of CHOICE_MODE_NONE
every time the list view is created on orientation change because a choice mode has not been explicitly defined in the list view layout file. The Android source where this happens - http://androidxref.com/4.4.2_r2/xref/frameworks/base/core/java/android/widget/AbsListView.java#815.
The solution is to add :
android:choiceMode="multipleChoice"
to the list view layout.
This also means that there is no need to manually store the list view selections in onSaveInstanceState()
and retrieve it in onViewStateRestored()
. It is done automatically by the fragment. So remove both these functions. Just start the action mode in onResume
:
@Override
public void onResume() {
super.onResume();
getLoaderManager().initLoader(0,null,this);
if (myListView.getCheckedItemCount() > 0 && actionMode == null) {
actionMode = ((ActionBarActivity) getActivity()).startSupportActionMode(new ContextualActionBarActionModeCallBack());
actionMode.setTitle(myListView.getCheckedItemCount() + " selected");
}
}
Note : If you have implemented the LoaderManager.LoaderCallBacks
interface and you need to access the adaptor items just after orientation change, do it in onLoadFinished()
after the adaptor has been loaded with the data source. Doing it in onResume()
would cause an NPE
.
Upvotes: 7