Android中如何将BluetoothSocket从一个Activity传递到另一个Activity?
传递BluetoothSocket到另一个Activity的方案
核心限制说明
BluetoothSocket 既不实现 Serializable 也不实现 Parcelable,所以不能直接通过Intent.putExtra()传递,必须通过共享对象的方式实现。
推荐方案:用后台Service管理蓝牙连接
这是Android蓝牙开发的标准实践,蓝牙连接属于长期运行的后台任务,放在Service中可以避免Activity销毁导致连接中断,同时能安全地在多个Activity间共享连接实例。
实现步骤:
- 创建蓝牙Service类:在Service中完成蓝牙连接的建立、维护,提供获取
BluetoothSocket的方法,或直接封装数据收发API。 - Activity绑定Service:连接Activity和控制Activity都通过
bindService()绑定到该Service,获取Service实例后即可访问蓝牙连接。
代码示例:
1. 蓝牙Service类
class BluetoothConnectionService : Service() { private var bluetoothSocket: BluetoothSocket? = null // 用于和绑定Activity通信的Binder private val binder = LocalBinder() inner class LocalBinder : Binder() { fun getService(): BluetoothConnectionService = this@BluetoothConnectionService } override fun onBind(intent: Intent): IBinder { return binder } // 对外提供获取Socket的方法 fun getBluetoothSocket(): BluetoothSocket? { return bluetoothSocket } // 建立蓝牙连接的逻辑 fun connectToDevice(device: BluetoothDevice) { // 省略设备连接的前置校验逻辑 bluetoothSocket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")) bluetoothSocket?.connect() } // 封装数据发送方法,控制Activity可直接调用 fun sendData(data: ByteArray) { bluetoothSocket?.outputStream?.write(data) } }
2. 连接Activity中绑定并建立连接
class ConnectionActivity : AppCompatActivity() { private lateinit var service: BluetoothConnectionService private var isServiceBound = false private val serviceConnection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, serviceBinder: IBinder) { val binder = serviceBinder as BluetoothConnectionService.LocalBinder service = binder.getService() isServiceBound = true // 用户选中设备后调用连接方法 val selectedDevice: BluetoothDevice = ... // 获取选中的蓝牙设备 service.connectToDevice(selectedDevice) // 连接成功跳转控制页 startActivity(Intent(this@ConnectionActivity, ControlActivity::class.java)) } override fun onServiceDisconnected(arg0: ComponentName) { isServiceBound = false } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 绑定Service Intent(this, BluetoothConnectionService::class.java).also { intent -> bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) } } override fun onDestroy() { super.onDestroy() if (isServiceBound) { unbindService(serviceConnection) isServiceBound = false } } }
3. 控制Activity中绑定Service并使用连接
class ControlActivity : AppCompatActivity() { private lateinit var service: BluetoothConnectionService private var isServiceBound = false private val serviceConnection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, serviceBinder: IBinder) { val binder = serviceBinder as BluetoothConnectionService.LocalBinder service = binder.getService() isServiceBound = true // 获取已建立的Socket或直接调用发送方法 val socket = service.getBluetoothSocket() // 启动数据收发逻辑 } override fun onServiceDisconnected(arg0: ComponentName) { isServiceBound = false } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 绑定Service Intent(this, BluetoothConnectionService::class.java).also { intent -> bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) } } override fun onDestroy() { super.onDestroy() if (isServiceBound) { unbindService(serviceConnection) isServiceBound = false } } // 示例:发送文本消息 private fun sendMessage(message: String) { if (isServiceBound) { service.sendData(message.toByteArray()) } } }
备选方案:使用单例类持有BluetoothSocket
如果场景简单,不需要长期后台连接,可以用单例类全局持有Socket实例,但要注意内存泄漏问题,在不需要时及时释放资源。
代码示例:
object BluetoothSocketHolder { var socket: BluetoothSocket? = null // 释放资源的方法,在应用退出或连接断开时调用 fun release() { socket?.close() socket = null } }
连接Activity中赋值:
// 连接成功后 BluetoothSocketHolder.socket = bluetoothSocket startActivity(Intent(this, ControlActivity::class.java))
控制Activity中获取:
val socket = BluetoothSocketHolder.socket // 使用socket进行数据收发
注意事项:
- 单例持有Socket会导致其生命周期与进程绑定,若Activity销毁但进程未结束,Socket会一直存在,可能引发内存泄漏,需在合适时机调用
release()。 - 多线程环境下需注意同步,可加锁或用线程安全方式访问。
内容的提问来源于stack exchange,提问作者Shady Abdulmunim
相关产品推荐
相关产品推荐

