Muszę przesłać niektóre dane z mojej aplikacji na system Android przez Bluetooth (do Arduino). Nie czytam/nie odbieram niczego z Arduino. W przypadku moich potrzeb z pojedynczym gwintem wybrałem IntentService. Po sparowaniu mój kod działa poprawnie po raz pierwszy, łącząc i wysyłając dane. Rozłączam się po wysłaniu danych bez błędów. Ale gdy próbuję połączyć drugi raz dalej, pojawia się następujący błąd, gdy próbuję myBluetoothSocket.connect():Problemy z połączeniem Bluetooth z IntentService
odczytu nie powiodła się, gniazdo mogą zamkniętych lub limitu czasu, przeczytaj ret: -1
Jedynym rozwiązaniem jest wyłączenie urządzenia Arduino i ponowne połączenie (nie pomoże to, gdy wymuszam zatrzymanie aplikacji i spróbuję ponownie się połączyć).
Zauważ, że wszystko działa poprawnie, gdy pojawia się 2 wątki (jeden do odczytu i zapisu), niezależnie od tego, ile razy łączę się i wysyła dane (udowadniając, że nie ma nic złego po stronie Arduino, "powstrzymując" starą połączenie).
Oto mój kod Android:
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);
}
}
}
Ja testowałem na Nexusie 5 i urządzeniach Samsung S5 (z systemem 5.1 i 5.0, odpowiednio).
mam wrażenie, problem leży w przy użyciu 'IntentService' zamiast regularnego' Service' i/lub zwyczaj 'wątek '. Z "IntentService" doc: * usługa jest uruchamiana w razie potrzeby, obsługuje każdy cel po kolei za pomocą wątku roboczego i zatrzymuje się, gdy zabraknie mu pracy. * Prawdopodobnie spowoduje to spustoszenie, jeśli próbujesz utrzymać BT połączenie przez intencje. – pathfinderelite
Dokładnie tego potrzebuję. Połącz, wyślij dane i zakończ połączenie. Następne połączenie prawdopodobnie nastąpi po bardzo długim okresie, tworząc nową usługę. Utrzymywanie wątków wydaje się być kłopotliwe w przypadku prostego użycia takiego jak ten. Zapewnia to również automatyczne leczenie jednego urządzenia na raz (część mojego przypadku użycia). – SlowAndSteady
To, co mówisz o Arduino, nie "powstrzymywanie" połączenia wydaje się rozsądne, ale fakt, że musisz ponownie włączyć Arduino, aby móc połączyć się ponownie, sprawia, że zastanawiam się. Może Arduino jakoś przechodzi w inny stan, jeśli czytasz i piszesz w tym samym wątku? (Wiem, brzmi to dziwnie.) Co się stanie, jeśli połączysz się z Arduino jednym telefonem, rozłączysz, a następnie spróbujesz połączyć się z drugim telefonem? Czy masz jakiś sposób, aby sprawdzić stan modemu bluetooth Arduino, aby sprawdzić, czy jest inaczej po pierwszym rozłączeniu, w porównaniu do wcześniejszego? – hBrent