3

我正在尝试使用 .我的Bluetoothgui将 androidSeekBar数据发送到arduino我改变了 SeekBar。SocketsOutputStreamSocketonSeekBarChanged()

 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if(seekBar.getId() == R.id.seekBar)
        {
            speed.setText(String.valueOf(progress));
            String outputData = String.valueOf(progress)+",";
            try
            {
            streams.write(outputData.getBytes());//writes data to OutputStream of Socket
            }catch (Exception e){
                Log.d("RTR","Sockets not yet formed");
            }

        }
    }

问题是我需要Accelerometer与当前值一起连续发送数据。SeekBar所以我尝试写入加速度计OutputStreamSocketfromonSensorChanged(SensorEvent event)方法。Result:Program not responding.

public void onSensorChanged(SensorEvent event) {

        if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
        {
            float accXYZ[] = event.values;

            float accX = accXYZ[0];
            float accY = accXYZ[1];
            float accZ = accXYZ[2];

            x.setText(String.format("%.2f",accX));
            y.setText(String.format("%.2f",accY));
            z.setText(String.format("%.2f",accZ));

            String outputData = x.getText().toString()+","+speed.getText().toString()+";";

            try{
                  streams.write(outputData.getBytes());
            }catch (Exception e){
                //Log.d("RTR","X");
            }

        }
    }

我知道这对 . 来说太重了UI Thread。我想我应该在方法中创建一个new Thread无限循环run()来连续发送数据。我怎样才能将加速度计和 SeekBar 数据连续发送到这个新线程。

或者我应该从这个新线程中收集 UIThread 的加速度计和 SeekBar 的数据。

In Short, how do I get data from UIThread to this new Thread.

请提供您知道的所有可能的解决方案,以解决我的问题以及我当前程序的任何并发症。

4

1 回答 1

6

一个很好的方法是使用内置Looper类。Looper 是为 Android 的 UI 线程提供支持的消息队列系统,您也可以在自己的线程中使用它。它的设计方式的好处在于它创建的垃圾收集负载非常少(取决于您使用的参数类型,它可以是无)。

我正在徒手写这个,所以你必须稍微修改一下才能让它工作,但它最终可能看起来像这样:

class LooperThread extends Thread {
    private static final int MSG_TYPE_OUTPUT_DATA = 0;
    private Handler mHandler;
    private volatile OutputStream mOutputStream;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                if (msg.what == MSG_TYPE_OUTPUT_DATA
                    && mOutputStream != null) {
                    //try-catch left out for brevity
                    mOutputStream.write(msg.obj.getBytes());
                }
            }
        };

        Looper.loop();
    }

    public void submitReading(String outputData) {
        mHandler.sendMessage(mHandler.obtainMessage(MSG_TYPE_OUTPUT_DATA, outputData);
    }
}

您的设置代码将执行以下操作:

private void setup() {
    Socket sock = setupBluetoothConnection();
    this.looperThread = new LooperThread();
    this.looperThread.setOutputStream(sock.getOutputStream());
    this.looperThread.start();
}

最后,您的传感器事件处理程序:

public void onSensorChanged(SensorEvent event) {

    if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
    {
        // snip...
        String outputData = x.getText().toString()+","+speed.getText().toString()+";";

        this.looperThread.submitReading(outputData);
    }
}

这给你的是一个单一的后台线程,它可以尽可能快地处理消息,并且你可以从任何其他线程以线程安全的方式提交消息。它们按顺序处理。

完成后,您需要注意正确关闭 looper 线程,并确保它可以处理丢失的套接字连接。

如果您需要将其限制为每秒一定的消息速率,事情会变得有点复杂。OutputStream.write 是一个阻塞操作,所以为了方便起见,我把它省略了。您要做的是System.nanoTime()在实例字段中注册您上次处理的消息,并在 handleMessage() 方法中,每当下一条消息在足够的时间过去之前进来时,您计算您必须等待多长时间才能处理消息。这比使用 sendMessageDelayed() 在“提交”端处理它要容易得多。

于 2013-02-17T14:30:39.453 回答