Tôi cần truyền một số dữ liệu từ ứng dụng Android của mình qua Bluetooth (sang Arduino). Tôi không đọc/nhận lại bất cứ điều gì từ Arduino. Đối với các nhu cầu đơn luồng của tôi, tôi đã đi với một IntentService. Sau khi ghép nối, mã của tôi hoạt động tốt cho lần đầu tiên tôi kết nối và gửi dữ liệu. Tôi ngắt kết nối sau khi gửi dữ liệu mà không có lỗi. Nhưng khi tôi cố gắng kết nối lần thứ hai trở đi, tôi nhận được lỗi sau khi tôi cố gắng myBluetoothSocket.connect():Sự cố kết nối Bluetooth với IntentService
đọc thất bại, ổ cắm có thể đóng cửa hoặc thời gian chờ, đọc ret: -1
Chỉ có giải pháp là tắt nguồn thiết bị Arduino và kết nối lại (nó không giúp được nếu tôi buộc dừng ứng dụng và thử kết nối lại).
Lưu ý rằng mọi thứ hoạt động tốt nếu tôi sinh ra 2 luồng (mỗi lần đọc và ghi) bất kể số lần tôi kết nối và gửi dữ liệu (do đó chứng minh không có gì sai ở phía Arduino, "giữ lại" cũ kết nối).
Đây là mã Android của tôi:
import android.app.IntentService;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.Context;
import android.os.Build;
import android.os.ParcelUuid;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.UUID;
public class DataTransmissionService extends IntentService {
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final String TAG = "DataTransmissionService";
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private OutputStream outStream = null;
private BluetoothDevice device = null;
public DataTransmissionService() {
super("DataTransmissionService");
}
@Override
protected void onHandleIntent(Intent intent) {
cleanup();
if (intent != null){
btAdapter = BluetoothAdapter.getDefaultAdapter();
pairedDeviceAddress = "already_paired_device_mac_addr";
try {
log.d(TAG, pairedDeviceAddress);
device = btAdapter.getRemoteDevice(pairedDeviceAddress);
log.d(TAG, "Device bond state : " + device.getBondState());
} catch (Exception e) {
log.e(TAG, "Invalid address: " + e.getMessage());
return;
}
try {
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
log.e(TAG, "Socket creation failed: " + e.getMessage());
return;
}
try {
if (!btSocket.isConnected()) {
btSocket.connect();
log.d(TAG, "Connected");
} else {
log.d(TAG, "Already Connected"); //flow never reaches here for any use case
}
} catch (IOException e) {
log.e(TAG, "btSocket.connect() failed : " + e.getMessage());
return;
}
try {
outStream = btSocket.getOutputStream();
} catch (IOException e) {
log.e(TAG, "Failed to get output stream:" + e.getMessage());
return;
}
sendData("test");
//cleanup(); called in onDestroy()
}
}
@Override
public void onDestroy(){
cleanup();
//notify ui
super.onDestroy();
}
private void cleanup(){
try {
if (outStream != null) {
outStream.close();
outStream = null;
}
} catch (Exception e) {
log.e(TAG, "Failed to close output stream : " + e.getMessage());
}
try {
if (btSocket != null) {
btSocket.close();
btSocket = null;
}
}catch (Exception e) {
log.e(TAG, "Failed to close connection : " + e.getMessage());
}
}
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
/*if(Build.VERSION.SDK_INT >= 10){
try {
final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
return (BluetoothSocket) m.invoke(device, MY_UUID);
} catch (Exception e) {
log.e(TAG, "Could not create Insecure RFComm Connection",e);
}
}*/
return device.createRfcommSocketToServiceRecord(MY_UUID);
}
private void sendData(String message) {
byte[] msgBuffer = message.getBytes();
log.d(TAG, "Sending : " + message);
try {
outStream.write(msgBuffer);
} catch (IOException e) {
log.e(TAG, "failed to write " + message);
}
}
}
tôi đã thử nghiệm trên Nexus 5 và các thiết bị Samsung S5 (chạy 5.1 và 5.0 tương ứng).
Tôi có một cảm giác vấn đề của bạn nằm trong việc sử dụng một 'IntentService' chứ không phải là một' Service' và/hoặc tùy chỉnh 'Chủ đề bình thường '. Từ tài liệu 'IntentService': * dịch vụ được khởi động khi cần thiết, xử lý từng Intent lần lượt bằng cách sử dụng một chuỗi công nhân, và dừng lại khi nó hết công việc. * Điều này có thể gây ra sự tàn phá nếu bạn đang cố gắng duy trì một BT kết nối giữa các mục đích. – pathfinderelite
Đó chính xác là những gì tôi cần. Kết nối, gửi dữ liệu và chấm dứt kết nối. Kết nối tiếp theo có thể sẽ xảy ra sau rất lâu, sinh ra một dịch vụ mới. Duy trì chủ đề có vẻ cồng kềnh cho một trường hợp sử dụng đơn giản như thế này. Điều này cũng tự động đảm bảo việc xử lý một thiết bị tại một thời điểm (một phần trong trường hợp sử dụng của tôi). – SlowAndSteady
Những gì bạn nói về Arduino không "giữ lại" kết nối có vẻ hợp lý, nhưng thực tế là bạn phải tắt Arduino và bật để có thể kết nối lại khiến tôi ngạc nhiên. Có lẽ Arduino bằng cách nào đó đi vào trạng thái khác nếu bạn đọc và viết trên cùng một luồng? (Tôi biết, có vẻ kỳ quặc.) Điều gì sẽ xảy ra nếu bạn kết nối với Arduino bằng một điện thoại, ngắt kết nối, sau đó thử kết nối với điện thoại thứ 2? Ngoài ra, bạn có bất kỳ cách nào để xem trạng thái của modem bluetooth của Arduino, để xem nếu nó bằng cách nào đó khác nhau sau khi bạn ngắt kết nối lần đầu tiên, so với trước đó? – hBrent