Android: AbsListView.setItemChecked() 导致 ActionMode 销毁并重新创建?
Android: AbsListView.setItemChecked() cause ActionMode Destroy and Recreate?
直接调用AbsListView.setItemChecked()
效果很好,ActionMode
会激活并创建。
mGridView.setItemChecked(pPosition, true);
但是当你先调用View.startActionMode()
,再调用AbsListView.setItemChecked()
时,startActionMode()
创建的ActionMode
会销毁,并重新创建setItemChecked()
].
我的问题是:先调用View.startActionMode()
时如何避免这个问题?
期待您的回复!谢谢!
为什么要重新创建一个新的?查看AbsListView.setItemChecked(int position, boolean value)
方法的源码,可以看到如下代码:
// Start selection mode if needed. We don't need to if we're unchecking something.
if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
if (mMultiChoiceModeCallback == null ||
!mMultiChoiceModeCallback.hasWrappedCallback()) {
throw new IllegalStateException("AbsListView: attempted to start selection mode " +
"for CHOICE_MODE_MULTIPLE_MODAL but no choice mode callback was " +
"supplied. Call setMultiChoiceModeListener to set a callback.");
}
mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
}
这意味着如果 mChoiceActionMode == null
,它将调用 startActionMode(mMultiChoiceModeCallback)
,因此将重新创建一个新的 ActionMode。
以及如何修复?
这里有一个简单的方法:使用 reflect 将 startActionMode()
创建的 ActionMode 分配给 AbsListView
.
中的私有字段 mChoiceActionMode
private void startActionMode() {
// Get the field "mMultiChoiceModeCallback" instance by reflect
AbsListView.MultiChoiceModeListener wrapperIns = null;
try {
Field wrapper = null;
wrapper = AbsListView.class.getDeclaredField("mMultiChoiceModeCallback");
wrapper.setAccessible(true);
wrapperIns = (AbsListView.MultiChoiceModeListener) wrapper.get(mMessageGridView);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
// Start the ActionMode, but not select any item.
ActionMode actionMode = mMessageGridView.startActionMode(wrapperIns);
// Assign actionMode to field "mChoiceActionMode" by reflect
try {
Field mChoiceActionMode = null;
mChoiceActionMode = AbsListView.class.getDeclaredField("mChoiceActionMode");
mChoiceActionMode.setAccessible(true);
mChoiceActionMode.set(mMessageGridView, actionMode);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
这里为什么要用wrapper?因为AbsListView.setMultiChoiceModeListener(MultiChoiceModeListener listener)
会包裹我们的mMultiChoiceModeListener,所以不能不直接使用。
直接调用AbsListView.setItemChecked()
效果很好,ActionMode
会激活并创建。
mGridView.setItemChecked(pPosition, true);
但是当你先调用View.startActionMode()
,再调用AbsListView.setItemChecked()
时,startActionMode()
创建的ActionMode
会销毁,并重新创建setItemChecked()
].
我的问题是:先调用View.startActionMode()
时如何避免这个问题?
期待您的回复!谢谢!
为什么要重新创建一个新的?查看AbsListView.setItemChecked(int position, boolean value)
方法的源码,可以看到如下代码:
// Start selection mode if needed. We don't need to if we're unchecking something.
if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
if (mMultiChoiceModeCallback == null ||
!mMultiChoiceModeCallback.hasWrappedCallback()) {
throw new IllegalStateException("AbsListView: attempted to start selection mode " +
"for CHOICE_MODE_MULTIPLE_MODAL but no choice mode callback was " +
"supplied. Call setMultiChoiceModeListener to set a callback.");
}
mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
}
这意味着如果 mChoiceActionMode == null
,它将调用 startActionMode(mMultiChoiceModeCallback)
,因此将重新创建一个新的 ActionMode。
以及如何修复?
这里有一个简单的方法:使用 reflect 将 startActionMode()
创建的 ActionMode 分配给 AbsListView
.
mChoiceActionMode
private void startActionMode() {
// Get the field "mMultiChoiceModeCallback" instance by reflect
AbsListView.MultiChoiceModeListener wrapperIns = null;
try {
Field wrapper = null;
wrapper = AbsListView.class.getDeclaredField("mMultiChoiceModeCallback");
wrapper.setAccessible(true);
wrapperIns = (AbsListView.MultiChoiceModeListener) wrapper.get(mMessageGridView);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
// Start the ActionMode, but not select any item.
ActionMode actionMode = mMessageGridView.startActionMode(wrapperIns);
// Assign actionMode to field "mChoiceActionMode" by reflect
try {
Field mChoiceActionMode = null;
mChoiceActionMode = AbsListView.class.getDeclaredField("mChoiceActionMode");
mChoiceActionMode.setAccessible(true);
mChoiceActionMode.set(mMessageGridView, actionMode);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
这里为什么要用wrapper?因为AbsListView.setMultiChoiceModeListener(MultiChoiceModeListener listener)
会包裹我们的mMultiChoiceModeListener,所以不能不直接使用。