Java Android:如何避免在切换按钮上同时执行操作

Java Android:如何避免在切换按钮上同时执行操作,java,android,sockets,Java,Android,Sockets,我正在开发一个应用程序,在这个应用程序中,我使用的是数字。打开和关闭操作,我执行的是不同的操作。它的家庭自动化应用程序,所以按钮是为交流,电视,灯等。我有固定的字节数组来打开和关闭这个设备。我正在使用套接字写入和读取这个字节数组。但我的问题是,当用户同时按下两个按钮时,按钮状态会闪烁,有时会显示ANR对话 以下是我的代码片段: @Override public void onClick(View v) { if(v.equals(fanDimmer1)) { i

我正在开发一个应用程序,在这个应用程序中,我使用的是数字。打开和关闭操作,我执行的是不同的操作。它的家庭自动化应用程序,所以按钮是为交流,电视,灯等。我有固定的字节数组来打开和关闭这个设备。我正在使用套接字写入和读取这个字节数组。但我的问题是,当用户同时按下两个按钮时,按钮状态会闪烁,有时会显示ANR对话

以下是我的代码片段:

@Override
public void onClick(View v) 
{
    if(v.equals(fanDimmer1))
    {
        if (fanDimmer1.isChecked()) {
        setByteArray((byte) 0x01, (byte) 0xff);
        } else {
        setByteArray((byte) 0x01, (byte) 0x00);
       }
    }
    else if(v.equals(fanDimmer2))
    {
        if (fanDimmer2.isChecked()) {
        setByteArray((byte) 0x02, (byte) 0xff);
        } else {
        setByteArray((byte) 0x02, (byte) 0x00);
     }
    } 
}
下面是SetByteArray()方法

更新:

下面是write()方法

初始化:

s = new Socket(ip, Integer.parseInt(port));
i = s.getInputStream();
o = s.getOutputStream();
更新2 这就是我在主线程中设置状态所做的

Runnable m_statusChecker = new Runnable() 
{
    @Override
    public void run() 
    {
        if (count == 0) {
            updateStatus();
            count = 1;
        } else {
            updateStatus1();
            count = 0;
        }
        m_handler.postDelayed(m_statusChecker,Integer.parseInt(interval));
    }

    private synchronized void updateStatus() 
    {
        // TODO Auto-generated method stub
        try {
            byte[] data1 = new byte[1024], packet1 = 
            { 
                (byte) 0x00,(byte) 0x00,(byte) 0x00, 
                (byte) 0x00,(byte) 0x00,(byte) 0x06, 
                (byte) 0x01,(byte) 0x01,(byte) 0x00,
                (byte) 0x00,(byte) 0x00,(byte) 0x19
            };

            write(packet1);
            i.read(data1, 0, 1024);

            byte_to_hex = ConversionMethods.bytesToHex(data1).substring(18, 26);

            char[] arr = byte_to_hex.toCharArray();
            for (int i = 0; i < arr.length - 1; i += 2) 
            {
                char temp = arr[i];
                arr[i] = arr[i + 1];
                arr[i + 1] = temp;
            }

            swapped_result=new String(arr);
            result = ConversionMethods.hexStringToNBitBinary(swapped_result, 32);

            int counter = 0;
            for( int i=0; i<result.length(); i++ ) 
            {
                if( result.charAt(i) == '1' )
                {
                    counter++;        
                }  
            }
            status=Integer.toString(counter);   
            runOnUiThread(updateButtons);

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
Runnable m_statusChecker=new Runnable()
{
@凌驾
公开募捐
{
如果(计数=0){
更新状态();
计数=1;
}否则{
updateStatus1();
计数=0;
}
m_handler.postDelayed(m_statusChecker,Integer.parseInt(interval));
}
私有同步的void updateStatus()
{
//TODO自动生成的方法存根
试一试{
字节[]数据1=新字节[1024],数据包1=
{ 
(字节)0x00,(字节)0x00,(字节)0x00,
(字节)0x00,(字节)0x00,(字节)0x06,
(字节)0x01,(字节)0x01,(字节)0x00,
(字节)0x00,(字节)0x00,(字节)0x19
};
编写(packet1);
i、 读取(数据1,0,1024);
byte_to_hex=ConversionMethods.bytesToHex(data1).substring(18,26);
char[]arr=byte_to_hex.tocharray();
对于(int i=0;i对于(int i=0;i使用单线程执行器按顺序发送数据。不要为每次数据传输创建新线程

Executor executor = Executors.newSingleThreadExecutor();

private void setByteArray(final byte a, final byte b) {
    executor.execute(new Runnable() { 
        public void run() { 
            // your code here
        } 
    });
}

所有Runnable都将一个接一个地执行。

了解您打算做什么后,我建议如下

  • 在你们的活动中有一个完整的值数组
  • 使单击事件处理程序修改值数组和
  • 之后,启动一个新的动态创建的
    AsyncTask
  • 在该异步任务(在主UI线程上执行)的
    onPreExecute
    中,禁用所有复选框
  • 在异步任务的
    doInBackground
    中,发送值并再次接收
  • onPostExecute
    中,根据新接收的数据设置所有复选框的状态,然后启用它们
如果响应不够,您需要决定如何处理设置冲突。我认为这取决于设置的性质。无论哪种方式,方案都可以轻松扩展:

  • onPreExecute
    中,复制当前值,但不要禁用复选框
  • doInBackground
    中,接收数组另一个副本中的值
  • onPostExecute
    (在主UI线程上执行)中,将收到的Vlaue与复选框的值进行比较。如果它们不相等,则启动新的AsyncTask以发送表示用户设置的值

这实现了一种冲突解决策略,这意味着用户的设置应该覆盖反馈。如果需要另一种策略,您可能会知道如何实现它。

因此我应该实现我的
setByteArray()
使用executor right的方法?更新了答案。如果您的写/读同步工作,这应该会起作用。谢谢,它提高了性能,但问题还没有解决!我可以在使用
Runnable设置按钮状态时使用此逻辑吗
?在实现您的想法后,它只会偶尔闪烁,这对我很好。你怎么办你的意思是“闪烁”?切换按钮可以是开的,也可以是的。你是如何得出你需要使用
equals()的结论的
用于比较
v
?--什么是
i
,为什么
o
被注释掉?--您是否知道,当用户按下按钮太快时,您可能会并行启动多个线程?
data2
发生了什么事?--
已同步的
没有做我认为您认为它做的事情。 ;)在处理过程中禁用按钮,并在完成后启用。此外,您可以随时取消正在执行的按钮并启动另一个按钮。@ClassStacker我已更新了问题,请检查它们为什么闪烁?以及您在主线程中做了什么导致ANR?我在给定代码中没有看到任何可能导致ANR的内容。为什么您是否创建iD/oD,但直接从i/o读/写?@Leonidos在主线程中,我正在为该切换按钮设置状态为on | off,以防有人切换风扇,那么它也应该在应用程序中显示为off。因此,我每秒检查一次该状态设置状态。感谢您的回答,我将尝试以这种方式实现
Runnable m_statusChecker = new Runnable() 
{
    @Override
    public void run() 
    {
        if (count == 0) {
            updateStatus();
            count = 1;
        } else {
            updateStatus1();
            count = 0;
        }
        m_handler.postDelayed(m_statusChecker,Integer.parseInt(interval));
    }

    private synchronized void updateStatus() 
    {
        // TODO Auto-generated method stub
        try {
            byte[] data1 = new byte[1024], packet1 = 
            { 
                (byte) 0x00,(byte) 0x00,(byte) 0x00, 
                (byte) 0x00,(byte) 0x00,(byte) 0x06, 
                (byte) 0x01,(byte) 0x01,(byte) 0x00,
                (byte) 0x00,(byte) 0x00,(byte) 0x19
            };

            write(packet1);
            i.read(data1, 0, 1024);

            byte_to_hex = ConversionMethods.bytesToHex(data1).substring(18, 26);

            char[] arr = byte_to_hex.toCharArray();
            for (int i = 0; i < arr.length - 1; i += 2) 
            {
                char temp = arr[i];
                arr[i] = arr[i + 1];
                arr[i + 1] = temp;
            }

            swapped_result=new String(arr);
            result = ConversionMethods.hexStringToNBitBinary(swapped_result, 32);

            int counter = 0;
            for( int i=0; i<result.length(); i++ ) 
            {
                if( result.charAt(i) == '1' )
                {
                    counter++;        
                }  
            }
            status=Integer.toString(counter);   
            runOnUiThread(updateButtons);

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
Runnable updateButtons=new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub 
        txt_status.setText(status);
        /*Log.v(TAG, "status is ::"+status);*/
        char[] c=result.toCharArray();
        int count=0;
        for (int i=0;i<24;i++)
        {
            count++;
            char j=c[i];
            Log.v(TAG, count+"::"+j);
            if(count==1)
                toggleButton=dimmerLight1;
            else if(count==2)
                toggleButton=dimmerLight2;
            else if(count==3)
                toggleButton=dimmerLight3;
            else if(count==4)
                toggleButton=dimmerLight4; 
            else if(count==5)
                toggleButton=dimmerLight5;
            ............
            ............

            if(j=='1')
                toggleButton.setChecked(true);
            else
                toggleButton.setChecked(false); 
        }

    }
};
Executor executor = Executors.newSingleThreadExecutor();

private void setByteArray(final byte a, final byte b) {
    executor.execute(new Runnable() { 
        public void run() { 
            // your code here
        } 
    });
}