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

Android蓝牙连接后台保持及跨Activity数据发送实现求助

解决Android全应用蓝牙持续连接及跨Activity发数据问题

你的核心问题是Activity生命周期限制导致蓝牙连接随页面销毁而断开,解决思路是把蓝牙核心逻辑迁移到后台Service中,因为Service独立于Activity生命周期,能在后台保持连接;同时通过组件绑定实现跨Activity调用蓝牙操作。下面是具体实现方案:

一、核心改造思路

  1. 将蓝牙扫描、配对、连接、收发数据的逻辑从BTActivity移到前台Service(避免系统因内存不足杀死后台服务)。
  2. 用Binder实现Activity与Service的绑定,让任意Activity能获取Service实例并调用蓝牙方法。
  3. 通过广播或LiveData实现Service向Activity传递蓝牙接收的数据。

二、具体代码实现

1. 创建蓝牙后台服务BluetoothService

这个Service负责所有蓝牙操作,并且在后台持续运行:

public class BluetoothService extends Service {
    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothSocket mBluetoothSocket;
    private InputStream mInputStream;
    private OutputStream mOutputStream;
    private Thread mReceiveThread;
    private boolean mIsConnected = false;

    // 用于Activity绑定Service的Binder
    private final IBinder mBinder = new LocalBinder();

    public class LocalBinder extends Binder {
        BluetoothService getService() {
            return BluetoothService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        // 启动前台服务(Android 8.0+必须,避免被系统杀死)
        startForeground(1, createForegroundNotification());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Service被杀死后尝试重启
        return START_STICKY;
    }

    // 创建前台通知(低优先级,不打扰用户)
    private Notification createForegroundNotification() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                "bluetooth_channel",
                "蓝牙服务",
                NotificationManager.IMPORTANCE_LOW
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }

        return new NotificationCompat.Builder(this, "bluetooth_channel")
                .setContentTitle("蓝牙连接中")
                .setContentText("保持设备连接")
                .setSmallIcon(R.drawable.ic_bluetooth)
                .build();
    }

    // 对外暴露的连接设备方法
    public boolean connectDevice(BluetoothDevice device) {
        if (mIsConnected) return true;
        try {
            // 替换为你使用的蓝牙UUID
            UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
            mBluetoothSocket = device.createRfcommSocketToServiceRecord(uuid);
            mBluetoothAdapter.cancelDiscovery(); // 断开扫描避免影响连接
            mBluetoothSocket.connect();
            
            mInputStream = mBluetoothSocket.getInputStream();
            mOutputStream = mBluetoothSocket.getOutputStream();
            mIsConnected = true;
            startReceiveThread(); // 启动数据接收线程
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            disconnect();
            return false;
        }
    }

    // 数据接收线程
    private void startReceiveThread() {
        mReceiveThread = new Thread(() -> {
            byte[] buffer = new byte[1024];
            int bytes;
            while (mIsConnected && mInputStream != null) {
                try {
                    bytes = mInputStream.read(buffer);
                    if (bytes > 0) {
                        String receivedData = new String(buffer, 0, bytes);
                        // 发送广播通知Activity收到数据
                        sendDataBroadcast(receivedData);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    disconnect();
                    break;
                }
            }
        });
        mReceiveThread.start();
    }

    // 对外暴露的发送数据方法
    public boolean sendData(String data) {
        if (!mIsConnected || mOutputStream == null) return false;
        try {
            mOutputStream.write(data.getBytes());
            mOutputStream.flush();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    // 断开连接
    public void disconnect() {
        mIsConnected = false;
        try {
            if (mInputStream != null) mInputStream.close();
            if (mOutputStream != null) mOutputStream.close();
            if (mBluetoothSocket != null) mBluetoothSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (mReceiveThread != null) {
            mReceiveThread.interrupt();
            mReceiveThread = null;
        }
    }

    // 发送广播传递数据给Activity
    private void sendDataBroadcast(String data) {
        Intent intent = new Intent("bluetooth_data_received");
        intent.putExtra("data", data);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        disconnect();
        stopForeground(true);
    }
}

2. 改造原BTActivity绑定Service

原Activity不再直接处理蓝牙逻辑,改为绑定Service并调用其方法:

public class BTActivity extends AppCompatActivity {
    private BluetoothService mBluetoothService;
    private boolean mIsServiceBound = false;
    private BroadcastReceiver mDataReceiver;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            BluetoothService.LocalBinder binder = (BluetoothService.LocalBinder) service;
            mBluetoothService = binder.getService();
            mIsServiceBound = true;
            // 这里可以初始化蓝牙操作,比如连接已配对设备
            // mBluetoothService.connectDevice(selectedDevice);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBluetoothService = null;
            mIsServiceBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bt);

        // 启动并绑定Service
        Intent serviceIntent = new Intent(this, BluetoothService.class);
        startService(serviceIntent); // 确保Service后台运行
        bindService(serviceIntent, mServiceConnection, BIND_AUTO_CREATE);

        // 注册广播接收器接收蓝牙数据
        mDataReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String data = intent.getStringExtra("data");
                updateReceivedDataUI(data); // 更新UI显示数据
            }
        };
        LocalBroadcastManager.getInstance(this)
                .registerReceiver(mDataReceiver, new IntentFilter("bluetooth_data_received"));
    }

    // 示例:发送数据按钮点击事件
    public void onSendDataClick(View view) {
        if (mIsServiceBound && mBluetoothService != null) {
            boolean success = mBluetoothService.sendData("来自BTActivity的消息");
            Toast.makeText(this, success ? "发送成功" : "发送失败", Toast.LENGTH_SHORT).show();
        }
    }

    private void updateReceivedDataUI(String data) {
        TextView tvReceived = findViewById(R.id.tv_received_data);
        tvReceived.setText(data);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 解绑Service,但Service仍在后台运行
        if (mIsServiceBound) {
            unbindService(mServiceConnection);
            mIsServiceBound = false;
        }
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mDataReceiver);
    }
}

3. 其他Activity调用蓝牙发送数据

任意Activity只需绑定Service,即可调用发送方法:

public class OtherActivity extends AppCompatActivity {
    private BluetoothService mBluetoothService;
    private boolean mIsServiceBound = false;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            BluetoothService.LocalBinder binder = (BluetoothService.LocalBinder) service;
            mBluetoothService = binder.getService();
            mIsServiceBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBluetoothService = null;
            mIsServiceBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);

        // 绑定Service
        Intent serviceIntent = new Intent(this, BluetoothService.class);
        bindService(serviceIntent, mServiceConnection, BIND_AUTO_CREATE);
    }

    // 示例:其他页面发送数据
    public void sendDataFromOtherPage(View view) {
        if (mIsServiceBound && mBluetoothService != null) {
            boolean success = mBluetoothService.sendData("来自OtherActivity的消息");
            Toast.makeText(this, success ? "发送成功" : "发送失败", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mIsServiceBound) {
            unbindService(mServiceConnection);
            mIsServiceBound = false;
        }
    }
}

三、关键配置与注意事项

  1. 权限配置:在AndroidManifest.xml中添加蓝牙相关权限:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 扫描需要 -->
<!-- Android 12+ 额外权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

<!-- 声明Service -->
<service android:name=".BluetoothService" />
  1. LiveData替代广播:如果需要生命周期感知的数据传递,可以在Service中使用MutableLiveData,Activity通过观察LiveData接收数据,比广播更安全简洁。
  2. 异常处理:建议在Service中添加蓝牙连接状态的回调,让Activity能实时感知连接状态变化。

内容的提问来源于stack exchange,提问作者Bhanu Prakash Pasupula

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:18:33