我目前有一个来自 Android 的BluetoothChat Example的工作 I/O 流,但遇到了问题。我的应用程序通过蓝牙连接到蓝牙模块,蓝牙模块又向模块物理连接的设备发送信号。
我的程序调用read()
输入流,如果有数据正在发送,程序执行顺利,没有问题。但是,流的实现方式没有针对中断连接的保护。如果模块从设备上被物理移除,或者设备没有发回任何信号,我的代码只是坐下来等待InputStream.read()
调用。
我的read()
电话看起来像这样:
try {
Log.i( "1) I/O", "available bits: " + mmInStream.available() );
bytes = mmInStream.read(buffer, 0, length);
Log.i( "2) I/O", "available bits: " + mmInStream.available() );
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (Exception e) {
Log.i(TAG, "Catch Statement" );
Message msg = mHandler.obtainMessage(MainMenu.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString( TOAST, "Device has disconnected from the Bluetooth Module." );
msg.setData(bundle);
mHandler.sendMessage(msg);
Log.e(TAG, "disconnected a", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothService.this.start();
//break;
}
当我的程序正确运行时,块Log
中的两个调用都try
返回0
for的值mmInStream.available()
。当输入流被中断时,第Log
一个调用返回 a 0
,第二个永远不会被调用。catch
然后,我的程序在每次到达块之前就崩溃了。
我一直在寻找几天来解决这个问题,并找到了许多解决方案,但它们要么不起作用,要么我不理解它们。
1) InputStream 使用扫描仪如下所示。这没有提供任何帮助,并且在阅读时也会超时。
Scanner scan = new Scanner(new InputStreamReader(mmInStream));
scan.useDelimiter( "[\\r\\n]+" );
String readIn;
try {
readIn = scan.next();
scan = null;
tempB = readIn.getBytes( Charset.forName( "US-ASCII" ) );
append = "\r\n".getBytes( Charset.forName( "US-ASCII" ) );
for( int i = 0; i < length; i++ ) {
if( i == length - 1 ) {
buffer[i] = append[1];
} else if ( i == length - 2 ) {
buffer[i] = append[0];
} else {
buffer[i] = tempB[i];
}
}
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (Exception e) {
Log.i(TAG, "Catch Statement" );
Message msg = mHandler.obtainMessage(MainMenu.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString( TOAST, "Device has disconnected from the Bluetooth Module." );
msg.setData(bundle);
mHandler.sendMessage(msg);
Log.e(TAG, "disconnected a", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothService.this.start();
//break;
}
2)我尝试运行一个线程,它会read
在 X 时间后取消调用,但它不能正常工作:
public void run(int length) throws IOException {
buffer = new byte[1024];
length1 = length;
Thread myThread = new Thread(new Runnable() {
public void run() {
try {
bytes = mmInStream.read( buffer, 0, length1 );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
synchronized (myThread) {
myThread.start();
try {
myThread.wait(500);
if(myThread.isAlive()) {
mmInStream.close();
Log.i( "InStream", "Timeout exceeded!");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
myThread.run();
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Message msg = mHandler.obtainMessage(MainMenu.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString( TOAST, "Device has disconnected from the Bluetooth Module." );
msg.setData(bundle);
mHandler.sendMessage(msg);
connectionLost();
BluetoothService.this.start();
}
在这两个选项不起作用之后,我一直在尝试研究Java NIO
or AsyncTask
,但是所有这些似乎都需要添加太多东西来识别 I/O 超时。我还看到有些Sockets
支持使用 的超时功能.setSoTimeout()
,但是这是一个BluetoothSocket
并且我发现他们不支持此功能。
由于没有I/O
类支持read()
将超时长度作为参数或完全超时的方法,在我看来,添加线程将是最简单的实现。这是错的吗?任何有关我在上述方法中做错了什么或如何合并Java NIO
/的信息AsyncTask
将不胜感激。
编辑:
这是我尝试过的新线程代码,我目前正在将其更改为给定答案显示的内容并尝试。如果之后它不起作用,我会发布。
Thread myThread = new Thread(new Runnable() {
public void run() {
try {
bytes = mmInStream.read( buffer, 0, length1 );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
synchronized (myThread) {
try {
myThread.wait(6000);
Log.i( "InStream", "After wait" );
if(myThread.isAlive()) {
Log.i( "InStream", "Timeout exceeded2!");
myThread.interrupt();
Log.i( "InStream", "Timeout exceeded!");
} else {
myThread.interrupt();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
Log.i( "InStream", "Exception Caught" );
e.printStackTrace();
}
}
编辑2:
我已经尝试过Dheerej
下面给出的答案。我得到一个IllegalMonitorStateException
函数wait()
调用。我尝试了答案中显示的内容,然后也尝试myThread.wait()
了代替Thread.currentThread.wait()
. 我假设正在引发此异常,因为这是myThread
正在创建对象并在另一个线程中运行。无论如何,下面的代码几乎与Dheerej's
答案相同。
int length1 = length;
Thread myThread = new Thread(new Runnable() {
public void run() {
buffer = new byte[1024];
try {
bytes = mmInStream.read(buffer, 0, length1);
} catch (IOException e) {
e.printStackTrace();
}
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
}
});
myThread.start();
try {
//Thread.currentThread().wait(500);
myThread.wait( 1000 ); // Line 533
} catch (InterruptedException e) {
e.printStackTrace();
//Log.i(TAG, "Catch Statement" );
Message msg = mHandler.obtainMessage(MainMenu.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString( TOAST, "Device has disconnected from the Bluetooth Module." );
msg.setData(bundle);
mHandler.sendMessage(msg);
Log.e(TAG, "disconnected a", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothService.this.start();
}
if (myThread.isAlive()) {
mmInStream.close(); // Alternatively try: myThread.interrupt()
}
这是生成的 LogCat。错误说它从第 533 行开始,也就是wait()
上面的调用:
12-28 17:44:18.765: D/BLZ20_WRAPPER(3242): blz20_wrp_poll: return 1
12-28 17:44:18.765: D/BLZ20_WRAPPER(3242): blz20_wrp_write: wrote 3 bytes out of 3 on fd 62
12-28 17:44:18.769: W/NATIVE CODE(3242): -4) baud9600=1, goodbaud=1
12-28 17:44:18.769: D/AndroidRuntime(3242): Shutting down VM
12-28 17:44:18.769: W/dalvikvm(3242): threadid=1: thread exiting with uncaught exception (group=0x40015578)
12-28 17:44:18.773: E/AndroidRuntime(3242): FATAL EXCEPTION: main
12-28 17:44:18.773: E/AndroidRuntime(3242): java.lang.IllegalMonitorStateException: object not locked by thread before wait()
12-28 17:44:18.773: E/AndroidRuntime(3242): at java.lang.Object.wait(Native Method)
12-28 17:44:18.773: E/AndroidRuntime(3242): at java.lang.Object.wait(Object.java:395)
12-28 17:44:18.773: E/AndroidRuntime(3242): at my.eti.commander.BluetoothService$ConnectedThread.run(BluetoothService.java:533)
12-28 17:44:18.773: E/AndroidRuntime(3242): at my.eti.commander.BluetoothService.read(BluetoothService.java:326)
12-28 17:44:18.773: E/AndroidRuntime(3242): at my.eti.commander.BluetoothService.changeitJava(BluetoothService.java:669)
12-28 17:44:18.773: E/AndroidRuntime(3242): at my.eti.commander.RelayAPIModel$NativeCalls.changeItJavaWrapper(RelayAPIModel.java:490)
12-28 17:44:18.773: E/AndroidRuntime(3242): at my.eti.commander.RelayAPIModel$NativeCalls.InitRelayJava(Native Method)
12-28 17:44:18.773: E/AndroidRuntime(3242): at my.eti.commander.MainMenu$1.handleMessage(MainMenu.java:547)
12-28 17:44:18.773: E/AndroidRuntime(3242): at android.os.Handler.dispatchMessage(Handler.java:99)
12-28 17:44:18.773: E/AndroidRuntime(3242): at android.os.Looper.loop(Looper.java:130)
12-28 17:44:18.773: E/AndroidRuntime(3242): at android.app.ActivityThread.main(ActivityThread.java:3687)
12-28 17:44:18.773: E/AndroidRuntime(3242): at java.lang.reflect.Method.invokeNative(Native Method)
12-28 17:44:18.773: E/AndroidRuntime(3242): at java.lang.reflect.Method.invoke(Method.java:507)
12-28 17:44:18.773: E/AndroidRuntime(3242): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
12-28 17:44:18.773: E/AndroidRuntime(3242): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
12-28 17:44:18.773: E/AndroidRuntime(3242): at dalvik.system.NativeStart.main(Native Method)
12-28 17:44:18.781: D/BLZ20_ASOCKWRP(3242): asocket_read
12-28 17:44:18.781: I/BLZ20_WRAPPER(3242): blz20_wrp_poll: nfds 2, timeout -1 ms
12-28 17:44:18.890: D/BLZ20_WRAPPER(3242): blz20_wrp_poll: transp poll : (fd 62) returned r_ev [POLLIN ] (0x1)
12-28 17:44:18.890: D/BLZ20_WRAPPER(3242): blz20_wrp_poll: return 1
12-28 17:44:18.890: D/BLZ20_WRAPPER(3242): blz20_wrp_read: read 5 bytes out of 5 on fd 62