Java 退出选择模式后,ListView选择将保持持久性

Java 退出选择模式后,ListView选择将保持持久性,java,android,android-listview,Java,Android,Android Listview,我有一个ListView子类,允许在上下文操作栏(CAB)处于活动状态时进行选择。CAB被设置为对onItemLongClick事件的回调: public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Inflate a menu resource providing context menu items MenuInflater inflater = mode.getMenuInflater();

我有一个ListView子类,允许在上下文操作栏(CAB)处于活动状态时进行选择。CAB被设置为对
onItemLongClick
事件的回调:

public boolean onCreateActionMode(ActionMode mode, Menu menu) {
    // Inflate a menu resource providing context menu items
    MenuInflater inflater = mode.getMenuInflater();
    inflater.inflate(context_menu, menu);
    getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    return true;
}
这很好,ListView按预期工作,当前选定的项目在触摸时保持高亮显示

关闭驾驶室时,我希望ListView恢复正常(即触摸模式)。问题在于,无论我尝试以何种方式清除最后选定的项目,该项目都会无限期地高亮显示:

public void onDestroyActionMode(ActionMode mode) {
    //Unselect any rows
    ListView lv = getListView();
    lv.clearChoices(); // Has no effect
    lv.setChoiceMode(ListView.CHOICE_MODE_NONE); // Has no effect on the highlighted item 
    lv.setFocusable(false); // Has no effect
    lv.setSelection(0); // Has no effect
    mActionMode = null;
}

有什么建议吗?

我面临同样的问题,因为请求布局也不能解决我的问题,所以我实施了一个适合我的小技巧。也许这是同一个问题,因为我在
CHOICE\u MODE\u SINGLE
CHOICE\u MODE\u NONE
之间切换

final ListView lv = getListView();
lv.clearChoices();
for (int i = 0; i < lv.getCount(); i++)
    lv.setItemChecked(i, false);
lv.post(new Runnable() {
    @Override
    public void run() {
        lv.setChoiceMode(ListView.CHOICE_MODE_NONE);
    }
});
当动作模式结束时,我调用这个代码片段<代码>清除选项确保不再检查所有项目(内部)。视图上的迭代确保所有当前可见的视图都已重置,不再进行检查

mListView.clearChoices();

for (int i = 0; i < mListView.getChildCount(); i++) {
    ((Checkable) mListView.getChildAt(i)).setChecked(false);
}

mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
mListView.clearChoices();
对于(int i=0;i
查看ListView源代码,解决此问题的唯一方法是将ListView设置为CHOICE_MODE_NONE,然后重新分配ListAdapter(无论选择模式如何,都会清除内部选择列表)

i、 e.在ListFragment/ListActivity中

getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
getListView().setAdapter(getListAdapter())

问题的主要原因是,一旦
ListView
选择模式切换到
CHOICE\u mode\u NONE
,框架将优化清除操作,因为它不再支持“选择”。通过手动清除选择状态,然后以延迟方式设置模式,我对上述解决方法进行了一些改进,这样框架将在将模式转到
CHOICE\u mode\u NONE
之前先清除状态

final ListView lv = getListView();
lv.clearChoices();
for (int i = 0; i < lv.getCount(); i++)
    lv.setItemChecked(i, false);
lv.post(new Runnable() {
    @Override
    public void run() {
        lv.setChoiceMode(ListView.CHOICE_MODE_NONE);
    }
});
final ListView lv=getListView();
lv.clearChoices();
对于(int i=0;i
我尝试了上面讨论的所有方法,但没有一种适合我。最后,我决定应用以下变通方法。关键是,

在多模式期间,我们将创建一个全新的视图,而不是重用“缓存”视图。效率不高,但至少“部分”解决了我的问题。

这是我定制的
ArrayAdapter

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // Key to solve this problem. When we are in multimode, we will not reusing the cached view.
    View rowView = this.multimode ? null : convertView;

    if (rowView == null) {
        LayoutInflater inflater = activity.getLayoutInflater();
        rowView = inflater.inflate(R.layout.watchlist_row_layout, null);
        ViewHolder viewHolder = new ViewHolder();
        viewHolder.textView0 = (TextView) rowView.findViewById(R.id.text_view_0);
        viewHolder.textView1 = (TextView) rowView.findViewById(R.id.text_view_1);
        viewHolder.textView2 = (TextView) rowView.findViewById(R.id.text_view_2);
        rowView.setTag(viewHolder);
    }
另外,我觉得在ActionMode.Callback中使用以下代码更安全,尽管我不确定它有多大帮助

    @Override
    public void onDestroyActionMode(ActionMode mode) {
        MyFragment.this.myArrayAdapter.setMultimode(false);

        // http://stackoverflow.com/questions/9754170/listview-selection-remains-persistent-after-exiting-choice-mode
        // Using View.post is the key to solve the problem.
        final ListView listView = MyFragment.this.getListView();
        listView.clearChoices();
        for (int i = 0, ei = listView.getChildCount(); i < ei; i++) {
            listView.setItemChecked(i, false);
        }
        listView.post(new Runnable() {
            @Override
            public void run() {
                listView.setChoiceMode(ListView.CHOICE_MODE_NONE);
            }
        });
        actionMode = null;
    }
@覆盖
公共void onDestroyActionMode(ActionMode模式){
MyFragment.this.myArrayAdapter.setmultimemode(false);
// http://stackoverflow.com/questions/9754170/listview-selection-remains-persistent-after-exiting-choice-mode
//使用View.post是解决这个问题的关键。
final ListView ListView=MyFragment.this.getListView();
clearChoices();
for(int i=0,ei=listView.getChildCount();i
旁注
使用MultiChoiceModeListener和CHOICE\u MODE\u MULTIPLE\u model将使这个bug消失。但是,对于API级别低于11的设备,将无法使用此解决方案。

不是错误。这种行为是支持多个Android应用程序所必需的。 因此,要显示选择状态,只需设置listview的选择模式和背景,以支持“列表项布局”的选择状态,如:

android:background=“?android:attr/activatedBackgroundIndicator”


仅供参考:

我在
API 17级遇到了这个问题,并通过以下操作解决了这个问题:

listView.clearChoices();
listView.invalidateViews();

我知道这个问题已经得到了回答,但上面的回答仍然给了我ListView维护的缓存/回收视图的问题,这些视图在卷回视图时并没有更新它的状态。 因此,上述解决方案略微更改为:

    lv.clearChoices();  

    ArrayList<View> list = new ArrayList<View>();
    lv.reclaimViews(list);
    for (View view : list) {
        ((Checkable) view).setChecked(false);
    }

    lv.setChoiceMode(lv.CHOICE_MODE_NONE);
lv.clearChoices();
ArrayList=新建ArrayList();
lv.视图(列表);
用于(视图:列表){
((可检查)视图).setChecked(false);
}
lv.setChoiceMode(lv.CHOICE\u MODE\u NONE);

这比使用getChildAt(i)要好,因为该方法jusg提供当前可见的视图,而不考虑内部缓存的视图,这些视图是不可见的。

我发现在这里工作的只有两种方法
(API 19)

  • 重置列表适配器,这是不可取的,因为它返回到列表的顶部
  • new Runnable
    中,将选择模式设置为
    choice\u mode\u NONE
如果在不使用
listView.post(new Runnable())
的情况下更改选择模式,则该模式不起作用。有人能解释一下为什么会这样吗

为没有发表评论而道歉;我没有名声


谢谢。

对我来说,公认的答案似乎不适用于看不见的物品,也不需要打电话

for (int i = 0; i < lv.getCount(); i++)
        lv.setItemChecked(i, false);
为了彻底解决我的问题,我打电话

lv.clearChoices();
lv.requestLayout();
在onDestroyActionMode()中

打电话

lv.setItemChecked(position, false)
onItemClick()
中,当它不处于操作模式时


但是,我没有确认调用
setItemChecked()
是否会导致一些性能问题

我不确定这是否为时已晚,只是想与大家分享一下。我为同一个页面创建了一个意图,这样一旦捕获了单击的数据,它就会重新创建一个新页面
getListView().clearChoices();
getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
getListView().clearChoices();
getListView().post(new Runnable() {
    @Override
    public void run() {
        getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
    }
});