Android如何在Fragment间传递BluetoothController并维持蓝牙连接
Android蓝牙Fragment切换时连接断开的解决方案
问题背景
开发基于蓝牙传输的Android项目,包含MainFragment和VillasFragment。需求是在两个Fragment间共享BluetoothController实例,实现VillasFragment通过该控制器发送数据,但切换Fragment时蓝牙连接会断开,重复初始化逻辑无法解决问题。
核心原因
两个Fragment各自创建独立的BluetoothController实例:
- 切换Fragment时,原MainFragment的控制器实例随Fragment销毁被回收,导致连接断开
- VillasFragment重新初始化控制器并调用
connect,相当于重建连接,可能出现连接失败或短暂断开
解决方案:将BluetoothController托管给Activity
把控制器的生命周期与宿主Activity绑定,确保Fragment切换时实例保持存活,两个Fragment共享同一个实例。
1. 在宿主Activity中初始化控制器
class MainActivity : AppCompatActivity() { lateinit var bluetoothController: BluetoothController lateinit var btAdapter: BluetoothAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initBtAdapter() val pref = getSharedPreferences(BluetoothConstants.PREFERENCES, MODE_PRIVATE) val mac = pref.getString(BluetoothConstants.MAC, "") bluetoothController = BluetoothController(btAdapter) } private fun initBtAdapter() { val bManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager btAdapter = bManager.adapter } // 提供给Fragment获取控制器的方法 fun getBluetoothController(): BluetoothController = bluetoothController }
2. 修改MainFragment使用Activity的控制器
移除Fragment内部的控制器初始化,改为从Activity获取:
class MainFragment : Fragment(), BluetoothController.Listener{ private lateinit var binding: FragmentMainBinding private lateinit var bluetoothController: BluetoothController override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 从Activity获取共享控制器 bluetoothController = (activity as MainActivity).getBluetoothController() bluetoothController.setListener(this) binding.bConnect.setOnClickListener { val pref = activity?.getSharedPreferences(BluetoothConstants.PREFERENCES, Context.MODE_PRIVATE) val mac = pref?.getString(BluetoothConstants.MAC, "") bluetoothController.connect(mac ?: "", this) } // 其余UI交互逻辑保持不变 } override fun onDestroyView() { super.onDestroyView() // 清空监听避免内存泄漏 bluetoothController.setListener(null) } // 其余方法保持不变 }
3. 修改VillasFragment共享控制器
同样从Activity获取已存在的控制器,无需重新初始化和连接:
class VillasFragment : Fragment(), BluetoothController.Listener{ private lateinit var binding: FragmentVillasBinding private lateinit var bluetoothController: BluetoothController override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 获取Activity中已初始化的控制器 bluetoothController = (activity as MainActivity).getBluetoothController() bluetoothController.setListener(this) // 直接使用控制器发送数据,无需调用connect binding.TVillas.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { val vt = progress binding.Ttext.text = "Тормоз: $vt" bluetoothController.sendMessage("vt=${vt};") } override fun onStartTrackingTouch(seekBar: SeekBar?) {} override fun onStopTrackingTouch(seekBar: SeekBar?) {} }) // 其余UI交互逻辑保持不变 } override fun onDestroyView() { super.onDestroyView() bluetoothController.setListener(null) } // 其余方法保持不变 }
4. 补充BluetoothController的监听切换方法
如果原BluetoothController没有提供切换监听的方法,需要添加:
class BluetoothController(...) { private var listener: Listener? = null // 添加此方法 fun setListener(newListener: Listener?) { this.listener = newListener } // 其余原有逻辑保持不变 }
关键注意点
- 禁止在VillasFragment中调用
connect方法,否则会打断现有连接 - 切换Fragment时通过
setListener更新监听者,确保回调能正确分发到当前显示的Fragment - 可选:在Fragment销毁时清空监听,避免潜在内存泄漏
内容的提问来源于stack exchange,提问作者Dunkeltod 13
相关产品推荐
相关产品推荐

