Android蓝牙重连后无法读取InputStream问题求助
Hey there! I totally get where you're coming from—Bluetooth in Android can be tricky when you're just starting out, especially with thread management. Let's break down why your reconnected InputStream isn't working and how to fix it.
The Root Cause
When you first connect, you probably start a thread to read from the InputStream. But when you disconnect, if you don't properly stop that thread and clean up the old stream/socket, the thread might still be running with an invalid (closed) InputStream. When you reconnect, you might be trying to reuse that old thread instead of creating a fresh one tied to the new BluetoothSocket's InputStream.
Step-by-Step Solution
1. Create a Reusable, Controllable Read Thread
First, let's wrap your InputStream reading logic into a dedicated thread class that you can start/stop easily. This way, every time you reconnect, you can spin up a new instance of this thread tied to the new socket.
public class BluetoothReadThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private boolean isRunning = true; private TextView mmTextView; public BluetoothReadThread(BluetoothSocket socket, TextView textView) { mmSocket = socket; mmTextView = textView; InputStream tmpIn = null; // Get the input stream from the socket try { tmpIn = socket.getInputStream(); } catch (IOException e) { Log.e("BluetoothThread", "Error getting input stream", e); } mmInStream = tmpIn; } public void run() { byte[] buffer = new byte[1024]; // Buffer for incoming data int bytes; // Keep listening to the InputStream while the thread is running while (isRunning && mmInStream != null) { try { // Read from the InputStream bytes = mmInStream.read(buffer); // Convert bytes to string final String incomingMessage = new String(buffer, 0, bytes); // Update TextView on UI thread (critical—can't touch UI from background thread!) mmTextView.post(new Runnable() { @Override public void run() { mmTextView.append(incomingMessage); } }); } catch (IOException e) { Log.e("BluetoothThread", "Input stream disconnected", e); break; } } } // Call this to stop the thread and clean up resources public void stopThread() { isRunning = false; try { if (mmInStream != null) { mmInStream.close(); } if (mmSocket != null) { mmSocket.close(); } } catch (IOException e) { Log.e("BluetoothThread", "Error closing resources", e); } } }
2. Update Your Connection/Disconnection Logic
Now, in your main activity, you'll need to track the active BluetoothReadThread and manage it properly during connect/disconnect/reconnect:
private BluetoothReadThread mReadThread; private BluetoothSocket mCurrentSocket; // Method to connect to HC-05 private void connectToHC05(BluetoothDevice device) { // First, make sure any existing connection is cleaned up if (mReadThread != null) { mReadThread.stopThread(); mReadThread = null; } if (mCurrentSocket != null && mCurrentSocket.isConnected()) { try { mCurrentSocket.close(); } catch (IOException e) { Log.e("MainActivity", "Error closing old socket", e); } mCurrentSocket = null; } // Create new socket and connect try { // Replace with your HC-05's UUID (usually 00001101-0000-1000-8000-00805F9B34FB for SPP) UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); mCurrentSocket = device.createRfcommSocketToServiceRecord(uuid); // Connect (note: this is blocking—should run on a background thread!) mCurrentSocket.connect(); // Start a new read thread with the new socket and your TextView mReadThread = new BluetoothReadThread(mCurrentSocket, yourTextView); mReadThread.start(); Toast.makeText(this, "Connected successfully!", Toast.LENGTH_SHORT).show(); } catch (IOException e) { Log.e("MainActivity", "Connection failed", e); Toast.makeText(this, "Connection failed", Toast.LENGTH_SHORT).show(); try { if (mCurrentSocket != null) { mCurrentSocket.close(); } } catch (IOException ex) { Log.e("MainActivity", "Error closing failed socket", ex); } } } // Method to disconnect from HC-05 private void disconnectHC05() { if (mReadThread != null) { mReadThread.stopThread(); mReadThread = null; } if (mCurrentSocket != null) { try { mCurrentSocket.close(); } catch (IOException e) { Log.e("MainActivity", "Error disconnecting", e); } mCurrentSocket = null; } Toast.makeText(this, "Disconnected", Toast.LENGTH_SHORT).show(); }
3. Key Things to Remember
- Never update UI from a background thread: We used
TextView.post()to safely update the TextView—this is crucial to avoid crashes. - Clean up resources every time: Always stop the old thread and close the socket/stream before reconnecting. If you skip this, you'll have stale threads holding onto closed streams.
- Run connection logic on a background thread: The
connect()method is blocking, so don't call it directly from the main UI thread (useAsyncTask,Coroutines, or a separate thread).
Final Checks
- Make sure you have the necessary Bluetooth permissions in your
AndroidManifest.xml:<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- For Android 12+, add these too --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> - Verify that your HC-05 is in the correct mode (pairing mode when first connecting, then data mode for communication).
This setup should let you disconnect and reconnect multiple times, with each new connection spawning a fresh thread to read from the InputStream. Let me know if you run into any specific issues with your existing code!
内容的提问来源于stack exchange,提问作者ongebear

