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

Android蓝牙写入完成后崩溃问题排查求助

问题根源分析

你的问题核心出在StartConfirm继承MainActivity这个设计上,Android中Activity继承意味着创建一个全新的子类实例,而不是复用原MainActivity的实例,这直接导致了两个关键问题:

  1. Broken pipe错误:StartConfirm作为MainActivity的子类,会初始化自己的mBluetoothConnection实例,当你从StartConfirm返回主页面后,原MainActivity的updateUi方法调用write时,可能连接已经被StartConfirm实例干扰(比如重复占用蓝牙资源、连接被意外关闭),导致写入失败抛出Broken pipe。
  2. Receiver未注册异常:MainActivity中应该有一个匿名广播接收器(日志里的MainActivity$1@dadacf9),子类StartConfirm继承后,会执行父类的生命周期逻辑,可能在子类实例中注册了接收器,但销毁时尝试注销的接收器要么是父类实例的,要么子类的接收器没正确注册,导致系统抛出“Receiver not registered”的异常。
解决方案

1. 取消StartConfirm对MainActivity的继承

把StartConfirm改成普通的Activity,不要继承MainActivity——继承Activity不是复用页面功能的正确方式,应该用组合模式或者抽离公共功能到工具类。

修改后的StartConfirm代码:

public class StartConfirm extends AppCompatActivity { // 改为继承AppCompatActivity
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.start_confirm_layout);
        // 不需要getIntent,因为是startActivityForResult启动的
    }

    public void OnStartConfirmation(View view) {
        Intent toStart = new Intent();
        setResult(1, toStart);
        finish();
    }

    public void OnNoStartConfirmation(View view) {
        Intent DoNotStart = new Intent();
        setResult(0, DoNotStart);
        finish();
    }
}

2. 抽离蓝牙功能为独立工具类

把蓝牙连接、写入等逻辑从MainActivity中抽出来,做成单例类,确保整个App中只有一个蓝牙连接实例,避免多Activity实例导致的资源冲突。

示例BluetoothManager类:

public class BluetoothManager {
    private static BluetoothManager instance;
    private BluetoothConnection mBluetoothConnection;

    private BluetoothManager() {
        // 初始化蓝牙连接逻辑
    }

    public static synchronized BluetoothManager getInstance() {
        if (instance == null) {
            instance = new BluetoothManager();
        }
        return instance;
    }

    public void write(byte[] bytes) {
        if (mBluetoothConnection != null) {
            mBluetoothConnection.write(bytes);
        }
    }

    // 其他蓝牙相关方法:连接、断开等
}

然后在MainActivity的updateUi中调用这个单例:

private void updateUi(int res) {
    BluetoothManager bluetoothManager = BluetoothManager.getInstance();
    if(res == 1) {
        byte[] bytes = "startup".getBytes(Charset.defaultCharset());
        bluetoothManager.write(bytes);
    } else if (res == 0) {
        byte[] bytes = "supp".getBytes(Charset.defaultCharset());
        bluetoothManager.write(bytes);
    } else {
        byte[] bytes = "sywa".getBytes(Charset.defaultCharset());
        bluetoothManager.write(bytes);
    }
}

3. 修复广播接收器的生命周期问题

检查MainActivity中广播接收器的注册逻辑,确保在onResume中注册,onPause中注销,避免在Activity销毁时尝试注销未注册的接收器:

示例代码(假设你的接收器是监听蓝牙状态):

private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 处理广播逻辑
    }
};

@Override
protected void onResume() {
    super.onResume();
    IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
    registerReceiver(mBluetoothReceiver, filter);
}

@Override
protected void onPause() {
    super.onPause();
    try {
        unregisterReceiver(mBluetoothReceiver);
    } catch (IllegalArgumentException e) {
        // 捕获接收器未注册的异常,避免崩溃
        Log.d("MainActivity", "Receiver already unregistered");
    }
}

4. 检查startActivityForResult的兼容性(可选)

如果你的App目标API级别是30+,startActivityForResult已经被废弃,建议改用registerForActivityResult,不过这不是导致当前崩溃的直接原因,但可以优化代码:

// 在MainActivity中定义
private ActivityResultLauncher<Intent> startConfirmLauncher = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() != RESULT_CANCELED) {
            // 处理结果
            int res = result.getResultCode();
            startPaintbot = res;
            updateUi(res);
        }
    }
);

// 替换原来的OnStartClick方法
public void OnStartClick(View view) {
    Intent GetStartConfirmation = new Intent(this, StartConfirm.class);
    startConfirmLauncher.launch(GetStartConfirmation);
}
总结

核心问题是错误地通过继承Activity来复用功能,导致多实例冲突。改成独立Activity+单例工具类的方式,既能复用蓝牙功能,又能避免生命周期和资源冲突的问题。同时修复广播接收器的注册注销逻辑,就能解决你遇到的崩溃和Broken pipe错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:43:27