交换列表中的项目后自定义列表适配器和 ViewHolder 模式出现问题

Posted

技术标签:

【中文标题】交换列表中的项目后自定义列表适配器和 ViewHolder 模式出现问题【英文标题】:Issue with custom list adapter and ViewHolder pattern after swaping items in list 【发布时间】:2015-07-16 16:16:51 【问题描述】:

Item 是一个自定义类,其中包含一个标题字符串和一个用于保存复选框状态的枚举。

private final List<Item> mItems = new ArrayList<Item>();

假设我的数组列表中有 3 个项目,我想交换项目 2 和 3 的位置。

// Move item down
public void moveDown(int position)
    if ( position < mItems.size() -1 ) 
        Collections.swap(mItems, position, position + 1);
        notifyDataSetChanged();
    

我可以看到,在调试 mItems 时,项目已正确交换。

接下来,将为每个数组列表项调用 getView 函数。

@Override
public View getView(int position, View convertView, ViewGroup parent) 

    final Item item = mItems.get(position);

    View myView = convertView;
    if ( null == myView )
    
        LayoutInflater inflater =  LayoutInflater.from(mContext);
        myView = inflater.inflate(R.layout.item, parent, false);

        ViewHolder  viewHolder  = new ViewHolder();
        viewHolder.title        = (TextView)       myView.findViewById(R.id.titleView);
        viewHolder.statusView   = (CheckBox)       myView.findViewById(R.id.statusCheckBox);

        myView.setTag(viewHolder);
        myView.setLongClickable(true);
    

    final ViewHolder myHolder = (ViewHolder) myView.getTag() ;

    // Display Title in TextView
    myHolder.title.setText(item.getTitle());

    // Set up Status CheckBox
    if ( item.getStatus() == Status.NOTDONE )
    
        myHolder.statusView.setChecked(false);
    
    else
    
        myHolder.statusView.setChecked(true);
    

    //  Must also set up an OnCheckedChangeListener, which is called when the user toggles the status checkbox
    myHolder.statusView
            .setOnCheckedChangeListener(new OnCheckedChangeListener() 
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
                
                    if ( isChecked == true ) 
                        item.setStatus(Status.DONE);
                    
                    else
                    
                        item.setStatus(Status.NOTDONE);
                    
                
            );

    return myView;


现在,说在开始时,这些是项目

项目:1 |标题 A |复选框状态:未选中 项目: 2 |标题 B |复选框状态:未选中 项目: 3 |标题 C |复选框状态:选中

在交换之后,我们得到了这个:

项目:1 |标题 A |复选框状态:未选中 项目: 2 |标题 C |复选框状态:选中 项目: 3 |标题 B |复选框状态:未选中

第二次 getView 被调用,当复选框状态被选中时,这将被调用:

myHolder.statusView.setChecked(true);

但奇怪的是:在那之后,我看到一个调用

 myHolder.statusView
   .setOnCheckedChangeListener(new OnCheckedChangeListener() 
       @Override
       public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
       
           if ( isChecked == true ) 
               item.setStatus(Status.DONE);
           
           else
           
               item.setStatus(Status.NOTDONE);
           
       
   );

item 指向 第三个项目(标题 'B')和相关的复选框,所以我最终错误地设置了 item 的状态3 完成

在我将 onCheckedChanged 侦听器设置为检查第 3 项后,我应该怎么做才能防止调用第 3 项?提前致谢。

【问题讨论】:

不使用view holder会发生这种情况吗? @pskink 不,它只在我使用 ViewHolder 时发生。如果我去掉 if ( null == myView ),那么行为看起来还可以 不,你不能删除“if (null == myView)”,它是为了视图重用,只是删除视图持有者模式,这是一个神话,它提高了性能,但几乎总是引入问题 【参考方案1】:

你能不能尝试在class而不是getview()中创建viewholder

【讨论】:

我不太明白,你能改写一下吗?【参考方案2】:

在交换两个项目后,我最终重新创建了受影响的视图。类变量会告诉 getView() 函数何时应该重新创建视图

【讨论】:

以上是关于交换列表中的项目后自定义列表适配器和 ViewHolder 模式出现问题的主要内容,如果未能解决你的问题,请参考以下文章

将数据从对话框插入 SQLi 后自定义列表视图不刷新

根据值使用自定义适配器编辑列表视图中的项目

片段中的自定义列表适配器

具有多个子项目的项目列表的自定义适配器?

在listview中的addTextChangedListener中使用自定义列表适配器

无法从android中的自定义列表视图中获取所选项目