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

Android蓝牙输出流写入触发空指针异常问题求助

解决Android蓝牙向Arduino写入数据时的空指针异常

看起来你遇到的问题是蓝牙连接建立后,写入输出流触发空指针,但接收数据正常——这通常意味着负责写入的线程或输出流对象没有被正确初始化。结合你给出的代码片段,我帮你梳理几个关键问题和修复方案:

1. 补全缺失的ConnectedThread类

你的代码里只定义了监听和连接线程,但负责实际数据读写的ConnectedThread完全缺失了,这大概率是空指针的根源。这个线程需要初始化输入/输出流,并提供写入数据的方法,添加如下代码:

private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket) {
        Log.d(TAG, "ConnectedThread: 创建连接线程");
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // 关闭连接进度对话框(如果之前显示的话)
        if(mProgressDialog != null){
            mProgressDialog.dismiss();
        }

        try {
            // 获取蓝牙Socket的输入输出流
            tmpIn = mmSocket.getInputStream();
            tmpOut = mmSocket.getOutputStream();
        } catch (IOException e) {
            Log.e(TAG, "ConnectedThread: 获取流失败: " + e.getMessage());
        }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        byte[] buffer = new byte[1024];  // 缓冲区存储传入的数据
        int bytes; // 读取的字节数

        // 持续监听输入流直到连接断开或发生异常
        while (true) {
            try {
                // 从输入流读取数据
                bytes = mmInStream.read(buffer);
                String incomingMessage = new String(buffer, 0, bytes);
                Log.d(TAG, "收到数据: " + incomingMessage);
                
                // 这里可以把数据传递到UI线程更新文本框,比如用Handler或接口回调
            } catch (IOException e) {
                Log.e(TAG, "ConnectedThread: 输入流读取异常: " + e.getMessage());
                break;
            }
        }
    }

    // 对外提供的写入数据方法
    public void write(byte[] bytes) {
        String text = new String(bytes, Charset.defaultCharset());
        Log.d(TAG, "发送数据: " + text);
        try {
            mmOutStream.write(bytes);
        } catch (IOException e) {
            Log.e(TAG, "ConnectedThread: 写入数据失败: " + e.getMessage());
        }
    }

    // 关闭连接
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}

2. 完善connected方法

你的代码里调用了connected(socket,mmDevice)但没有实现,这个方法需要初始化并启动ConnectedThread:

private void connected(BluetoothSocket socket, BluetoothDevice device) {
    Log.d(TAG, "connected: 启动数据读写线程");

    // 创建并启动负责数据传输的线程
    mConnectedThread = new ConnectedThread(socket);
    mConnectedThread.start();
}

3. 添加对外暴露的发送数据接口

在BluetoothService类中添加一个方法,让你的Activity可以调用它发送数据:

// 向蓝牙设备发送数据的对外方法
public void write(byte[] out) {
    // 确保连接线程已初始化
    ConnectedThread r;
    synchronized (this) {
        if (mConnectedThread == null) return;
        r = mConnectedThread;
    }
    r.write(out);
}

4. 补全startClient方法的逻辑

你的代码里startClient方法写到一半中断了,确保它能正确完成连接流程:

public void startClient(BluetoothDevice device, UUID uuid){
    Log.d(TAG, "startClient: Started.");
    // 初始化连接进度对话框
    mProgressDialog = ProgressDialog.show(mContext, "连接中...", "请稍候", true);

    // 取消正在进行的旧连接线程
    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    // 创建新的连接线程并启动
    mConnectThread = new ConnectThread(device, uuid);
    mConnectThread.start();
}

5. 发送数据的注意事项

在Activity中调用发送方法时,要确保:

  • 蓝牙连接已经完全建立(即mConnectedThread不为null)
  • 发送的数据转换为合法的字节数组(比如字符串转字节:"forward".getBytes())

示例调用:

// 假设你已经获取了BluetoothService实例
if (bluetoothService != null) {
    bluetoothService.write("open_light".getBytes());
}

问题根源说明

接收数据正常说明蓝牙物理连接是通的,但写入时触发空指针,本质是负责写入的ConnectedThread或其内部的mmOutStream没有被初始化——因为你之前的代码里完全缺少这个线程的定义和启动逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 03:56:03