Saat ini saya mencoba menangani Pengecualian yang aneh saat membuka BluetoothSocket di Nexus 7 (2012) saya, dengan Android 4.3 (Build JWR66Y, saya kira pembaruan 4.3 kedua). Saya telah melihat beberapa posting terkait (misalnya /programming/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), tetapi tampaknya tidak ada yang memberikan solusi untuk masalah ini. Selain itu, seperti yang disarankan dalam utas ini, memasangkan ulang tidak membantu, dan terus mencoba untuk terhubung (melalui loop bodoh) juga tidak berpengaruh.
Saya berurusan dengan perangkat tertanam (adaptor mobil OBD-II noname, mirip dengan http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- LAMPU-DENGAN-TELEPON-ANDA-Oceanside.jpg ). Ponsel Android 2.3.7 saya tidak memiliki masalah koneksi, dan Xperia rekan kerja (Android 4.1.2) juga berfungsi. Google Nexus lain (saya tidak tahu apakah 'One' atau 'S', tetapi bukan '4') juga gagal dengan Android 4.3.
Berikut adalah Cuplikan pembentukan koneksi. Ini berjalan di Thread-nya sendiri, dibuat dalam Layanan.
private class ConnectThread extends Thread {
private static final UUID EMBEDDED_BOARD_SPP = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
private BluetoothAdapter adapter;
private boolean secure;
private BluetoothDevice device;
private List<UUID> uuidCandidates;
private int candidate;
protected boolean started;
public ConnectThread(BluetoothDevice device, boolean secure) {
logger.info("initiliasing connection to device "+device.getName() +" / "+ device.getAddress());
adapter = BluetoothAdapter.getDefaultAdapter();
this.secure = secure;
this.device = device;
setName("BluetoothConnectThread");
if (!startQueryingForUUIDs()) {
this.uuidCandidates = Collections.singletonList(EMBEDDED_BOARD_SPP);
this.start();
} else{
logger.info("Using UUID discovery mechanism.");
}
/*
* it will start upon the broadcast receive otherwise
*/
}
private boolean startQueryingForUUIDs() {
Class<?> cl = BluetoothDevice.class;
Class<?>[] par = {};
Method fetchUuidsWithSdpMethod;
try {
fetchUuidsWithSdpMethod = cl.getMethod("fetchUuidsWithSdp", par);
} catch (NoSuchMethodException e) {
logger.warn(e.getMessage());
return false;
}
Object[] args = {};
try {
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice deviceExtra = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
Parcelable[] uuidExtra = intent.getParcelableArrayExtra("android.bluetooth.device.extra.UUID");
uuidCandidates = new ArrayList<UUID>();
for (Parcelable uuid : uuidExtra) {
uuidCandidates.add(UUID.fromString(uuid.toString()));
}
synchronized (ConnectThread.this) {
if (!ConnectThread.this.started) {
ConnectThread.this.start();
ConnectThread.this.started = true;
unregisterReceiver(this);
}
}
}
};
registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
registerReceiver(receiver, new IntentFilter("android.bluetooth.device.action.UUID"));
fetchUuidsWithSdpMethod.invoke(device, args);
} catch (IllegalArgumentException e) {
logger.warn(e.getMessage());
return false;
} catch (IllegalAccessException e) {
logger.warn(e.getMessage());
return false;
} catch (InvocationTargetException e) {
logger.warn(e.getMessage());
return false;
}
return true;
}
public void run() {
boolean success = false;
while (selectSocket()) {
if (bluetoothSocket == null) {
logger.warn("Socket is null! Cancelling!");
deviceDisconnected();
openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
}
// Always cancel discovery because it will slow down a connection
adapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
bluetoothSocket.connect();
success = true;
break;
} catch (IOException e) {
// Close the socket
try {
shutdownSocket();
} catch (IOException e2) {
logger.warn(e2.getMessage(), e2);
}
}
}
if (success) {
deviceConnected();
} else {
deviceDisconnected();
openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
}
}
private boolean selectSocket() {
if (candidate >= uuidCandidates.size()) {
return false;
}
BluetoothSocket tmp;
UUID uuid = uuidCandidates.get(candidate++);
logger.info("Attempting to connect to SDP "+ uuid);
try {
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(
uuid);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(
uuid);
}
bluetoothSocket = tmp;
return true;
} catch (IOException e) {
logger.warn(e.getMessage() ,e);
}
return false;
}
}
Kode gagal bluetoothSocket.connect()
. Saya mendapatkan a java.io.IOException: read failed, socket might closed, read ret: -1
. Ini adalah sumber yang sesuai di GitHub: https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504
Dipanggil melalui readInt (), dipanggil dari https : //github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319
Beberapa metadata dump dari soket bekas menghasilkan informasi berikut. Ini persis sama di Nexus 7 dan ponsel 2.3.7 saya.
Bluetooth Device 'OBDII'
Address: 11:22:33:DD:EE:FF
Bond state: 12 (bonded)
Type: 1
Class major version: 7936
Class minor version: 7936
Class Contents: 0
Contents: 0
Saya memiliki beberapa adaptor OBD-II lainnya (lebih ekspansif) dan semuanya berfungsi. Apakah ada kemungkinan, bahwa saya melewatkan sesuatu atau mungkinkah ini bug di Android?
Jawaban:
Saya akhirnya menemukan solusi. Keajaiban tersembunyi di balik kap
BluetoothDevice
kelas (lihat https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037 ).Sekarang, ketika saya menerima pengecualian itu, saya membuat contoh fallback
BluetoothSocket
, mirip dengan kode sumber di bawah ini. Seperti yang Anda lihat, memanggil metode tersembunyicreateRfcommSocket
melalui refleksi. Saya tidak tahu mengapa metode ini disembunyikan. Kode sumber mendefinisikannya seolah-public
olah ...connect()
maka tidak akan gagal lagi. Saya masih mengalami beberapa masalah. Pada dasarnya, ini terkadang memblokir dan gagal. Reboot Perangkat SPP (colok / colokkan) membantu dalam kasus seperti itu. Kadang-kadang saya juga mendapatkan permintaan Penyandingan lainconnect()
bahkan setelah perangkat sudah diikat.MEMPERBARUI:
di sini adalah kelas lengkap, berisi beberapa kelas bertingkat. untuk implementasi nyata ini bisa diadakan sebagai kelas terpisah.
sumber
Fallback failed. Cancelling. java.io.IOException: Connection refused
Tolong bantu.baik, saya memiliki masalah yang sama dengan kode saya, dan itu karena sejak android 4.2 bluetooth stack telah berubah. jadi kode saya berjalan dengan baik di perangkat dengan android <4.2, di perangkat lain saya mendapatkan pengecualian yang terkenal "gagal baca, soket mungkin tertutup atau batas waktu, baca ret: -1"
Masalahnya ada pada
socket.mPort
parameternya. Saat Anda membuat soket menggunakansocket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
,mPort
mendapat nilai integer " -1 ", dan nilai ini tampaknya tidak berfungsi untuk android> = 4.2, jadi Anda perlu menyetelnya ke " 1 ". Kabar buruknya adalah bahwacreateRfcommSocketToServiceRecord
hanya menerima UUID sebagai parameter dan tidakmPort
begitu kita harus menggunakan pendekatan lain. Jawabannya diposting oleh @matthes juga bekerja untuk saya, tetapi saya disederhanakan:socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);
. Kita perlu menggunakan kedua atribut soket, yang kedua sebagai cadangan.Jadi kodenya adalah (untuk menghubungkan ke SPP di perangkat ELM327):
sumber
mPort
parameter! imho alur kerjanya tetap sama, saya hanya membungkus hal-hal dengan beberapa kelas yang menerapkan antarmuka.Pertama, jika Anda perlu berbicara dengan perangkat bluetooth 2.x, dokumentasi ini menyatakan bahwa:
Saya tidak berpikir itu akan berhasil, tetapi hanya dengan mengganti UUID dengan
00001101-0000-1000-8000-00805F9B34FB
itu berfungsi. Namun, kode ini tampaknya menangani masalah versi SDK, dan Anda bisa mengganti fungsinyadevice.createRfcommSocketToServiceRecord(mMyUuid);
dengantmp = createBluetoothSocket(mmDevice);
setelah menentukan metode berikut:Kode sumber bukan milik saya, tetapi berasal dari situs web ini .
sumber
Saya mengalami gejala yang sama seperti yang dijelaskan di sini. Saya dapat menghubungkan sekali ke printer bluetooth tetapi koneksi berikutnya gagal dengan "soket tertutup" tidak peduli apa yang saya lakukan.
Saya merasa agak aneh bahwa solusi yang dijelaskan di sini diperlukan. Setelah melalui kode saya, saya menemukan bahwa saya lupa menutup InputStream dan OutputSteram soket dan tidak menghentikan ConnectedThreads dengan benar.
ConnectedThread yang saya gunakan sama dengan contoh di sini:
http://developer.android.com/guide/topics/connectivity/bluetooth.html
Perhatikan bahwa ConnectThread dan ConnectedThread adalah dua kelas yang berbeda.
Kelas apa pun yang memulai ConnectedThread harus memanggil interrupt () dan cancel () di thread. Saya menambahkan mmInStream.close () dan mmOutStream.close () dalam metode ConnectedTread.cancel ().
Setelah menutup utas / aliran / soket dengan benar, saya dapat membuat soket baru tanpa masalah.
sumber
Sebenarnya saya telah menemukan masalahnya.
Kebanyakan orang yang mencoba membuat koneksi menggunakan
socket.Connect();
mendapatkan pengecualian dipanggilJava.IO.IOException: read failed, socket might closed, read ret: -1
.Dalam beberapa kasus juga tergantung pada perangkat Bluetooth Anda, karena terdapat dua jenis Bluetooth yang berbeda, yaitu BLE (hemat energi) dan Klasik.
Jika Anda ingin memeriksa jenis perangkat Bluetooth Anda, berikut kodenya:
Saya sudah mencoba selama berhari-hari untuk memecahkan masalah, tetapi sejak hari ini saya telah menemukan masalahnya. Sayangnya, solusi dari @matthes masih memiliki beberapa masalah seperti yang dia katakan, tetapi inilah solusi saya.
Saat ini saya bekerja di Xamarin Android, tetapi ini juga harus berfungsi untuk platform lain.
LARUTAN
Jika terdapat lebih dari satu perangkat pasangan, maka Anda harus menghapus perangkat pasangan lainnya. Jadi simpan hanya yang ingin Anda hubungkan (lihat gambar di kanan).
Pada gambar kiri Anda melihat bahwa saya memiliki dua perangkat yang dipasangkan, yaitu "MOCUTE-032_B52-CA7E" dan "Blue Easy". Itulah masalahnya, tetapi saya tidak tahu mengapa masalah itu terjadi. Mungkin protokol Bluetooth mencoba mendapatkan beberapa informasi dari perangkat Bluetooth lain.
Namun,
socket.Connect();
pekerjaannya bagus sekarang, tanpa masalah. Jadi saya hanya ingin membagikan ini, karena kesalahan itu sangat mengganggu.Semoga berhasil!
sumber
Pada versi Android yang lebih baru, saya menerima kesalahan ini karena adaptor masih menemukan ketika saya mencoba untuk menyambung ke soket. Meskipun saya memanggil metode cancelDiscovery pada adaptor Bluetooth, saya harus menunggu hingga callback ke metode onReceive () BroadcastReceiver dipanggil dengan tindakan BluetoothAdapter.ACTION_DISCOVERY_FINISHED.
Setelah saya menunggu adaptor menghentikan penemuan, maka panggilan hubungkan pada soket berhasil.
sumber
Anda meletakkan
registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
dengan "bluetooth" dieja "bleutooth".sumber
Jika seseorang mengalami masalah dengan Kotlin, saya harus mengikuti jawaban yang diterima dengan beberapa variasi:
Semoga membantu
sumber
Perangkat Bluetooth dapat beroperasi dalam mode klasik dan LE secara bersamaan. Terkadang mereka menggunakan alamat MAC yang berbeda tergantung pada cara Anda menghubungkan. Panggilan
socket.connect()
menggunakan Bluetooth Classic, jadi Anda harus memastikan perangkat yang Anda dapatkan saat memindai benar-benar perangkat klasik.Mudah untuk memfilter hanya untuk perangkat Klasik, namun:
if(BluetoothDevice.DEVICE_TYPE_LE == device.getType()){ //socket.connect() }
Tanpa pemeriksaan ini, ini adalah kondisi balapan, apakah pemindaian hibrid akan memberi Anda perangkat Klasik atau perangkat BLE terlebih dahulu. Ini mungkin tampak sebagai ketidakmampuan intermiten untuk terhubung, atau sebagai perangkat tertentu yang dapat terhubung dengan andal sementara yang lain tampaknya tidak pernah bisa.
sumber
Saya juga menghadapi masalah ini, Anda bisa menyelesaikannya dengan 2 cara, seperti yang disebutkan sebelumnya menggunakan refleksi untuk membuat soket Kedua adalah, klien mencari server dengan UUID yang diberikan dan jika server Anda tidak berjalan paralel dengan klien maka ini terjadi. Buat server dengan UUID klien tertentu dan kemudian dengarkan dan terima klien dari sisi server. Ini akan berfungsi.
sumber
Saya mengalami masalah ini dan memperbaikinya dengan menutup aliran input dan output sebelum menutup soket. Sekarang saya dapat memutuskan sambungan dan terhubung lagi tanpa masalah.
https://stackoverflow.com/a/3039807/5688612
Di Kotlin:
sumber
Jika bagian lain dari kode Anda telah membuat koneksi dengan soket yang sama dan UUID, Anda mendapatkan kesalahan ini.
sumber
Bahkan saya memiliki masalah yang sama, akhirnya memahami masalah saya, saya mencoba menyambung dari (di luar jangkauan) jangkauan jangkauan Bluetooth.
sumber
Saya punya masalah ini dan solusinya adalah menggunakan GUID ajaib khusus.
Saya curiga bahwa ini adalah UUID yang berfungsi:
Namun, saya belum mencoba semuanya.
sumber
Dengan menambahkan tindakan filter, masalah saya teratasi
sumber
Saya juga menerima hal yang sama
IOException
, tetapi saya menemukan demo sistem Android: proyek "BluetoothChat" berhasil. Saya menentukan masalahnya adalah UUID.Jadi saya mengganti saya
UUID.fromString("00001001-0000-1000-8000-00805F9B34FB")
keUUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")
dan itu berfungsi paling banyak adegan, hanya kadang-kadang perlu me-restart perangkat Bluetooth;sumber