3

这是我的阵列适配器。它为列表中的每个开关按钮分配一个侦听器,该侦听器取决于数据库给出的 id(使用 传递devices.id)。但是由于某种原因,开关侦听器从开关中获取了正确的状态。

出于调试目的,无论状态如何,我都只是在更改侦听器上使用相同的。因此,无论我打开还是关闭它,它都运行相同的功能。

我的问题是有时当我打开第 1 个开关时,第 7 个开关打开,n 当我打开第 2 个开关时,第 8 个开关打开。我做错了什么,但我无法弄清楚。第 6、7、8 个开关不能正常工作。

您可以在 LCD 中看到,当我按顺序打开开关时,它必须给我输出“12345678”。但它不是。相反,它给出了“12345112”。

编辑:Emil Adz 给出的答案有效。给我输出“12345678”。但我有一个问题。如果我打开开关1,向下滚动直到它不可见并向上滚动,开关重置为关闭。为什么会这样?

无线控制器截图 无线控制器截图 液晶输出

public class DevListAdapter extends ArrayAdapter<Devices>{

    Context context; 
    int layoutResourceId;    
    Devices data[] = null;
    private TextView txt = null;
    
    public DevListAdapter(Context context, int layoutResourceId, Devices[] data) {
        super(context, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.context = context;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Log.d("WCAM","GetView");
        View row = convertView;
        DeviceHolder holder = null;
        Devices devices = data[position];
        String id = devices.id;

        Log.d("WCAM","Inflator");
        if(row == null)
        {
            Log.d("WCAM","True");
            LayoutInflater inflater = ((Activity)context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);

            holder = new DeviceHolder();
            holder.devTxt = (TextView)row.findViewById(R.id.devdesc);
            holder.nameTxt = (TextView)row.findViewById(R.id.devname);
            holder.toggleSwitch = (Switch)row.findViewById(R.id.toggleswitch);
            holder.txt = (TextView) row.findViewById(R.id.debug);
            final int i;
            
            if(id.matches("1")) {
                i = 0x31;
            }
            else if(id.matches("2")) {
                i = 0x32;
            }
            else if(id.matches("3")) {
                i = 0x33;
            }
            else if(id.matches("4")) {
                i = 0x34;
            }
            else if(id.matches("5")) {
                i = 0x35;
            }
            else if(id.matches("6")) {
                i = 0x36;
            }
            else if(id.matches("7")) {
                i = 0x37;
            }
            else {
                i = 0x38;
            }
            holder.toggleSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    Control._service.write(i);
                }
             });
            
            row.setTag(holder);
        }
        else
        {
            Log.d("WCAM","False");
            holder = (DeviceHolder)row.getTag();
        }
        
        holder.devTxt.setText(devices.dev);
        holder.nameTxt.setText(devices.name);
        holder.txt.setText(id);
        
        return row;
    }
    
    static class DeviceHolder
    {
        TextView devTxt;
        TextView txt;
        TextView nameTxt;
        Switch toggleSwitch;
    }
}

devices 是 Devices.java 的一个对象

public class Devices {
    public String dev;
    public String name;
    public String id;
    public Devices(){
        super();
    }
    
    public Devices(String _id, String dev, String name) {
        super();
        this.dev = dev;
        this.name = name;
        this.id = _id;
    }
}
4

3 回答 3

1

试试这样:

public class DevListAdapter extends ArrayAdapter<Devices>{

Context context; 
int layoutResourceId;    
Devices data[] = null;
private TextView txt = null;

public DevListAdapter(Context context, int layoutResourceId, Devices[] data) {
    super(context, layoutResourceId, data);
    this.layoutResourceId = layoutResourceId;
    this.context = context;
    this.data = data;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    Log.d("WCAM","GetView");
    DeviceHolder holder = null;
    Devices devices = data[position];
    String id = devices.id;

    Log.d("WCAM","Inflator");
        Log.d("WCAM","True");
        LayoutInflater inflater = ((Activity)context).getLayoutInflater();
        row = inflater.inflate(layoutResourceId, parent, false);

        holder = new DeviceHolder();
        holder.devTxt = (TextView)row.findViewById(R.id.devdesc);
        holder.nameTxt = (TextView)row.findViewById(R.id.devname);
        holder.toggleSwitch = (Switch)row.findViewById(R.id.toggleswitch);
        holder.txt = (TextView) row.findViewById(R.id.debug);
        final int i;

        if(id.matches("1")) {
            i = 0x31;
        }
        else if(id.matches("2")) {
            i = 0x32;
        }
        else if(id.matches("3")) {
            i = 0x33;
        }
        else if(id.matches("4")) {
            i = 0x34;
        }
        else if(id.matches("5")) {
            i = 0x35;
        }
        else if(id.matches("6")) {
            i = 0x36;
        }
        else if(id.matches("7")) {
            i = 0x37;
        }
        else {
            i = 0x38;
        }
        holder.toggleSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Control._service.write(i);
            }
         });

    holder.devTxt.setText(devices.dev);
    holder.nameTxt.setText(devices.name);
    holder.txt.setText(id);

    return row;
}

基本上由于某种原因,我多次遇到这个问题。当您使用时convertView,所有列表都会变得疯狂。请注意它会产生性能这一事实,但我没有找到解决此问题的适当解决方案。更重要的是,当列表不是那么大时,它并没有太大变化。

更新: 首先看看这个指南:

可多次点击的 ListView

与那里的复选框状态一样,您将看到:

    //setting data into the the ViewHolder.
    holder.title.setText(RowData.getName());
    holder.checked.setChecked(RowData.isChecked());

    //return the row view.
    return convertView;

因此,在您的情况下,在此代码之后:

    holder.devTxt.setText(devices.dev);
    holder.nameTxt.setText(devices.name);
    holder.txt.setText(id);

你应该添加类似的东西:

   holder.toggleSwitch.setChecked(devices.isChecked());

并在您onCheckedChanged坚持状态更改。

于 2013-05-05T17:49:53.203 回答
1

我的切换视图遇到了同样的问题。经过大量搜索和阅读,我发现这个问题是Android推广的视图优化的结果。它尝试重用视图对象。这确实有效,但如果你不注意,或者只是不知道行为(像我一样),就会发生一些非常奇怪的结果。

无论如何,我找到了这个简单的解决方案:

像您一样将我的视图存储在 ViewHolder 中并编写 onCheckedChanged 事件。诀窍是,在设置是否检查开关并定义 CheckedChange 侦听器之前,我只需将回调重置为 null,这样可以确保不会触发另一个开关的事件。

这是片段:

...
viewHolder.switchView.setOnCheckedChangeListener(null);
viewHolder.switchView.setChecked(myObject.getStatus() > 0);
...
viewHolder.switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                ...
            }
        });

myObject 是存储游标数据的最终对象。

无论是否检查开关,您都必须调用 setChecked 方法。

希望它可以帮助某人!

于 2015-08-18T13:57:09.357 回答
0

您的 ListView 当前将开关的状态与行的位置相关联,而不是与行的实际内容相关联。当用户滚动浏览您的 ListView 并且其内容被回收时,它会根据位置放入开关值。

要解决此问题,您需要以与实际行相关联的方式保存开关的状态。Android: Problem With ListViews and CheckBoxes 处理完全相同的问题,但使用复选框。它对于解决这类问题非常有用

于 2013-05-05T18:36:00.277 回答