【问题标题】:Ui updating twice in listview in androidUI在android的listview中更新两次
【发布时间】:2014-02-18 07:23:27
【问题描述】:

我正在开发一个安卓应用程序。在这个列表视图中,每个项目都有复选框。

默认情况下所有项目都被选中。对于复选框,我已应用 onClickListener。每当用户单击复选框时,我都会在当前定位的 bean 类中设置值 true。

一切都很好。但是 Ui 正在更新两个替代项目而不是一个。 例如,如果我点击第二个复选框,那么第四个复选框也在用户界面中更新。点击监听器只调用一次。

下面是适配器类中点击监听的代码。

 public View getView(final int position, View convertView, ViewGroup parent) {

     LayoutInflater inflater = (LayoutInflater) mcontext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View listview = convertView;

        listview = inflater.inflate(R.layout.edit_group_users_item, null);

        //Get all the fields of the layout
        userTV = (TextView) listview.findViewById(R.id.code);
        checkbox = (CheckBox) listview.findViewById(R.id.checkBox1);

        userTV.setText(userList.get(position).getUserName());

        checkbox.setChecked(true);

        checkbox.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                    Log.v("Position is:", ""+position); 
                    Log.v("Befoer checkbox status is:", ""+GroupsAdapter.group_users.get(position).isSelected());   
                if(!GroupsAdapter.group_users.get(position).isSelected()) {                     
                    //set the value to true in the user bean
                    GroupsAdapter.group_users.get(position).setSelected(true);
                    checkbox.setChecked(true);
                } else {
                    //set the value to false in the user bean
                    GroupsAdapter.group_users.get(position).setSelected(false);
                    checkbox.setChecked(false);
                }

            } 
        });
return listview;
}

我不知道出了什么问题。请告诉我如何解决上述问题。

【问题讨论】:

  • checkbox.setChecked(true);在 clickListener 将每一行设置为选中之前!!!
  • 建议:维护一个列表,在其中只存储那些被检查的项目。并在 getView 方法中检查该项目是否存在于列表中,如果是,则检查它,否则不检查。在 onclick 监听器中,调用 Activity 中仅调用 notifyDatasetChanged 的​​方法。

标签: android checkbox android-listview onclicklistener


【解决方案1】:

这是recycle listView,你必须为每个项目设置默认值,所以你需要改变你的代码如下:

public View getView(final int position, View convertView, ViewGroup parent) {

     LayoutInflater inflater = (LayoutInflater) mcontext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View listview = convertView;

        listview = inflater.inflate(R.layout.edit_group_users_item, null);

        //Get all the fields of the layout
        userTV = (TextView) listview.findViewById(R.id.code);
        checkbox = (CheckBox) listview.findViewById(R.id.checkBox1);

        userTV.setText(userList.get(position).getUserName());


        // this line changed
        checkbox.setTag(position);
        checkbox.setChecked(GroupsAdapter.group_users.get(position).isSelected());
        // ***********
        checkbox.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                    CheckBox ch = (CheckBox) v;
                    // add this line too for getting poition of clicked
                    int pos = (Integer) v.getTag();
                    Log.v("Position is:", ""+pos); 
                    Log.v("Befoer checkbox status is:", ""+GroupsAdapter.group_users.get(pos).isSelected());   
                if(!GroupsAdapter.group_users.get(pos).isSelected())                      

                   GroupsAdapter.group_users.get(pos).setSelected(true);
               else   
                    GroupsAdapter.group_users.get(pos).setSelected(false);

             Activity.adapter.notifyDataSetChanged();  
             // adapter is your this adapter that you used change visibility to 
             //  public static and refresh your list in here 
            } 
        });
return listview;
}

告诉我结果。

【讨论】:

  • 没有遇到同样的问题。例如,当我点击第 2 项时,第 4 项也在 ui 中更新,如果我点击第 1 项,则第 3 项也在 ui 中更新跨度>
  • 我只使用了你的代码,但仍然遇到同样的问题
  • 再次检查我的编辑,我编辑 onClick 方法,更改适配器的可见性并使用此代码
  • 由于适配器而出现错误,我应该使用什么来代替适配器?
【解决方案2】:
 checkbox.setChecked(true);

不要在代码中添加这个。如果要默认选中,则在xml中设置选中状态。在此处添加甚至会导致之前未选中的值再次被选中。

请也试试这个

checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

    if (isChecked) {

    } else {

    }

    }
});    

【讨论】:

  • 我已经评论了上述行并进行了测试,但仍然遇到同样的问题。
  • 同样在这个 onCheckedChanged 调用两次
【解决方案3】:

由于 ListView Recycling,您正面临问题。这很正常,很多人都面临着同样的问题。首先你应该看this Answer了解ListView Recycling

现在回到你的问题

if I click on the 2nd check box, then the 4th check box is also updating in user interface.

您将自行处理。我也遇到了同样的问题并解决了。

注意:这是一个相当冗长的方法,您应该集中精力并按照以下步骤操作,我相信您会像我一样解决您的问题:)。

第 1 步:

创建一个数据库类,我假设你知道 SQLite 数据库。创建一个表,在其中添加两个属性:

1) 位置(主键) 2) 名称(您的列表视图项的名称)

制作三个函数:

1) insertChecksItems(int position, String name)(当你点击ckeckbox时将这两个东西插入数据库)

2)(检查listView当前位置是否被检查的功能)

public boolean isChecked(int position) 
{
        Cursor c = db.rawQuery("select * from " + DATABASE_TABLE +" where position=" + position, null);

        int count = c.getCount();

        c.close();

        if(count>0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

3) public void deleteChecks(int position)

第 2 步:

在您的适配器类中声明一个布尔数组,并通过以下函数从您的adapter class constructor 对其进行初始化:

boolean[] checks;

public YourAdapterConstructor()
{
   initChecks();
}

private void initChecks()
{
        checks = new boolean[userList.size()]; 

        for(int i = 0; i < checks.length; i++)
        {
            checks[i] = false; //initialize the whole checks array false initially (you can set it true if you want all items checked at first time) 
        }

        for(int i = 0; i < userList.size(); i++)
        {
            if(db.isChecked(i))
            {
                checks[i] = true;
            }
            else
            {
                checks[i] = false;
            }
        }
    }

第 3 步:最后在您的 adapter getView() method 中,您应该执行类似的操作

public View getView(final int position, View convertView, ViewGroup parent) {

     LayoutInflater inflater = (LayoutInflater) mcontext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View listview = convertView;

        listview = inflater.inflate(R.layout.edit_group_users_item, null);

        //Get all the fields of the layout
        userTV = (TextView) listview.findViewById(R.id.code);
        checkbox = (CheckBox) listview.findViewById(R.id.checkBox1);

        userTV.setText(userList.get(position).getUserName());

        checkbox.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) 
            {
             if(checks[position])
              {
                db.deleteChecks(position);

                checks[position] = false;

                notifyDataSetChanged();
            }
            else
            {

                db.insertChecksItems(position, userList.get(position).getUserName());

                checks[position] = true;

                notifyDataSetChanged();
            }

            } 
        });

          if(checks[position] == true) // this check is must because based on this you will be able to check that which position of my listview was selected last time you selected
    {           
        checkbox.setChecked(true);
    }
    else
    {
        checkbox.setChecked(false);
    }

return listview;
}

更新:在你的适配器类中你应该覆盖notifyDataSetChanged() method

@Override
    public void notifyDataSetChanged() 
    {
        if(checks.length != userList.size())
        {
            initChecks();

            System.out.println("Checks Length = " + checks.length + "  Data Size = " + data.size());
        }

        super.notifyDataSetChanged();
    }

【讨论】:

    猜你喜欢
    • 2014-01-06
    • 2015-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多