You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法建立蓝牙连接且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();
    }
}

关键修复点说明

  1. 主线程阻塞解决:把acceptConnect的逻辑放到子线程startBluetoothServer里,避免主线程被阻塞。
  2. 完善异常处理:所有IO操作都添加了null判断和异常捕获,防止空指针和IO异常导致崩溃。
  3. 修复代码完整性:补全了beginListenForData的catch块,确保代码可编译运行。
  4. 优化ListView逻辑:把参会人员数据提前初始化,OnItemClickListener只设置一次,避免在getView里重复执行,提升性能和稳定性。
  5. 蓝牙开启回调处理:在onActivityResult里处理用户开启蓝牙的结果,确保蓝牙开启后才启动服务端。

内容的提问来源于stack exchange,提问作者h_h10a

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:52:42