无法建立蓝牙连接且App崩溃,求排查acceptConnect实现问题
解决蓝牙连接导致App崩溃的问题
看起来你遇到的崩溃主要来自几个关键问题,尤其是acceptConnect方法的实现和主线程阻塞的问题,我帮你拆解并修复:
核心问题分析
- 主线程执行阻塞操作:
accept()是阻塞方法,你直接在onCreate里调用acceptConnect,会导致主线程被卡住,触发ANR(应用无响应)甚至崩溃。Android明确禁止在主线程做网络/蓝牙这类阻塞IO操作。 - 代码不完整:
beginListenForData方法里的catch块没写完(catc少了h),这会导致编译错误,运行时直接崩溃。 - 空指针风险:如果
temp.accept()抛出异常,bTSocket会保持null,后续调用bTSocket.getInputStream()会直接抛空指针异常。 - ListView的Adapter逻辑错误:在
getView里重复创建数据集合、设置OnItemClickListener,不仅性能极差,还可能引发意外的视图复用问题。
修复后的完整代码示例
我把这些问题都修复了,重点调整了蓝牙连接的线程处理,完善了异常捕获,优化了ListView的逻辑:
public class Menu extends AppCompatActivity { private BluetoothAdapter BTAdapter; public static int REQUEST_BLUETOOTH = 1; private BluetoothSocket bTSocket; private BluetoothServerSocket mmServerSocket; InputStream mmInputStream; Thread workerThread; byte[] readBuffer; int readBufferPosition; int counter; volatile boolean stopWorker; static ArrayList<String> people = new ArrayList<>(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.menu); //Set socket to initially null bTSocket = null; //Enable bluetooth BTAdapter = BluetoothAdapter.getDefaultAdapter(); // Phone does not support Bluetooth so let the user know and exit. if (BTAdapter == null) { new AlertDialog.Builder(this) .setTitle("Not compatible") .setMessage("Your phone does not support Bluetooth") .setPositiveButton("Exit", (dialog, which) -> System.exit(0)) .setIcon(android.R.drawable.ic_dialog_alert) .show(); return; // 提前返回,避免后续代码执行 } //Request enabling if (!BTAdapter.isEnabled()) { Intent enableBT = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBT, REQUEST_BLUETOOTH); } else { // 蓝牙已开启才启动连接监听 startBluetoothServer(); } // 初始化ListView逻辑,移出Adapter的getView final ListView mylv = findViewById(R.id.mylv); // 提前准备好参会人员数据 ArrayList<String> attendees = new ArrayList<>(); attendees.add("Taylor"); attendees.add("Emily"); attendees.add("Mark"); attendees.add("Steve"); ArrayAdapter<String> adapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, people) { @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); TextView text = view.findViewById(android.R.id.text1); String person = getItem(position); if (attendees.contains(person)) { text.setTextColor(Color.rgb(0, 153, 76)); } else { text.setTextColor(Color.RED); } return view; } }; mylv.setAdapter(adapter); // 设置点击事件,只需要一次 mylv.setOnItemClickListener((parent, view, position, id) -> { String person = (String) parent.getItemAtPosition(position); if (attendees.contains(person)) { Toast.makeText(Menu.this, person + " is here", Toast.LENGTH_LONG).show(); } else { Toast.makeText(Menu.this, person + " is not here", Toast.LENGTH_LONG).show(); } }); mylv.setVisibility(View.GONE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_BLUETOOTH) { if (resultCode == RESULT_OK) { // 用户同意开启蓝牙后启动服务端 startBluetoothServer(); } else { Toast.makeText(this, "蓝牙未开启,无法使用功能", Toast.LENGTH_SHORT).show(); } } } // 把蓝牙服务端逻辑放到子线程 private void startBluetoothServer() { new Thread(() -> { BluetoothServerSocket temp = null; Log.d("SERVERCONNECT", "Attempting to create server"); UUID mUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //Standard SerialPortService ID try { temp = BTAdapter.listenUsingInsecureRfcommWithServiceRecord("Attend", mUUID); } catch (IOException e) { Log.d("SERVERCONNECT", "Could not get a BluetoothServerSocket:" + e.toString()); return; } mmServerSocket = temp; while (!Thread.currentThread().isInterrupted()) { try { Log.d("SERVERCONNECT", "Waiting for connection..."); bTSocket = temp.accept(); Log.d("SERVERCONNECT", "Connected to client!"); } catch (IOException e) { Log.d("SERVERCONNECT", "Could not accept an incoming connection:" + e.toString()); break; } if (bTSocket != null) { // 连接成功后启动数据监听 runOnUiThread(() -> Toast.makeText(Menu.this, "蓝牙连接成功", Toast.LENGTH_SHORT).show()); beginListenForData(); try { temp.close(); // 关闭服务端,只接受一个连接 } catch (IOException e) { Log.d("SERVERCONNECT", "Could not close ServerSocket:" + e.toString()); } break; } } }).start(); } public void back(View view) { Intent intent = new Intent(Menu.this, List.class); closeConnect(); startActivity(intent); } void closeConnect() { stopWorker = true; try { if (mmInputStream != null) { mmInputStream.close(); } } catch (IOException e) { Log.d("SERVERCONNECT", "Could not close InputStream:" + e.toString()); } try { if (bTSocket != null) { bTSocket.close(); } } catch (IOException e) { Log.d("SERVERCONNECT", "Could not close BluetoothSocket:" + e.toString()); } try { if (mmServerSocket != null) { mmServerSocket.close(); } } catch (IOException e) { Log.d("SERVERCONNECT", "Could not close BluetoothServerSocket:" + e.toString()); } } void beginListenForData() { final Handler handler = new Handler(Looper.getMainLooper()); // 确保Handler绑定主线程 final byte delimiter = 10; // ASCII newline stopWorker = false; readBufferPosition = 0; readBuffer = new byte[1024]; workerThread = new Thread(() -> { while (!Thread.currentThread().isInterrupted() && !stopWorker) { try { if (mmInputStream == null) { mmInputStream = bTSocket.getInputStream(); } int bytesAvailable = mmInputStream.available(); if (bytesAvailable > 0) { byte[] packetBytes = new byte[bytesAvailable]; mmInputStream.read(packetBytes); for (int i = 0; i < bytesAvailable; i++) { byte b = packetBytes[i]; if (b == delimiter) { byte[] encodedBytes = new byte[readBufferPosition]; System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length); final String data = new String(encodedBytes, "US-ASCII"); readBufferPosition = 0; // 在主线程更新UI或处理数据 handler.post(() -> { Log.d("BLUETOOTH_DATA", "Received: " + data); // 可以把接收到的数据添加到people列表,更新Adapter people.add(data); ((ArrayAdapter) findViewById(R.id.mylv).getAdapter()).notifyDataSetChanged(); }); } else { readBuffer[readBufferPosition++] = b; } } } } catch (IOException e) { Log.d("SERVERCONNECT", "Error reading data:" + e.toString()); stopWorker = true; } } }); workerThread.start(); } }
关键修复点说明
- 主线程阻塞解决:把
acceptConnect的逻辑放到子线程startBluetoothServer里,避免主线程被阻塞。 - 完善异常处理:所有IO操作都添加了null判断和异常捕获,防止空指针和IO异常导致崩溃。
- 修复代码完整性:补全了
beginListenForData的catch块,确保代码可编译运行。 - 优化ListView逻辑:把参会人员数据提前初始化,
OnItemClickListener只设置一次,避免在getView里重复执行,提升性能和稳定性。 - 蓝牙开启回调处理:在
onActivityResult里处理用户开启蓝牙的结果,确保蓝牙开启后才启动服务端。
内容的提问来源于stack exchange,提问作者h_h10a
相关产品推荐
相关产品推荐

