课程介绍:协程在BLE开发中的角色与挑战

1.1 BLE开发的异步之痛

做BLE开发的朋友都懂——这玩意儿天生就是异步的。你发起一个连接,不知道什么时候回调;你发现服务,又得等;你读写特征值,还得等。每一步都是回调,嵌套起来那叫一个酸爽。

我几年前接手过一个BLE室内定位项目,代码里三层回调嵌套,连接成功回调里写发现服务,发现服务回调里写读写特征值。说实话,改一个逻辑要翻好几屏代码,心累。

更头疼的是生命周期。你的页面关掉了,BLE回调还在跑,它持有的那个Activity引用就成了泄漏点。你想想看,用户进进出出页面几次,内存就噌噌往上涨。

总结一下BLE开发的几个痛点:

  • 回调地狱 —— 连接、发现、读写,每一步嵌套一步
  • 生命周期脆弱 —— 页面销毁后回调仍在执行
  • 错误处理分散 —— 每个回调都要单独处理异常
  • 取消逻辑繁琐 —— 手动维护取消状态,容易遗漏

1.2 协程——异步救星,但...

协程的出现确实让BLE代码清爽了不少。用 suspend 函数把异步操作包起来,代码就变成了线性写法。说白了,就是用同步的写法搞定异步的逻辑。

你看这个对比:

维度 传统回调模式 协程模式
代码可读性 三层回调嵌套,维护成本高 线性书写,一目了然
生命周期管理 手动取消,靠自觉 作用域自动取消
错误处理 每个回调单独try-catch 统一 try-catch,干净
泄漏风险 回调持有引用 协程不取消同样泄漏

看到最后一行了吗?嗯,这里要注意——协程并没有消灭泄漏,它只是换了一种泄漏的方式。我以前也觉得用了协程就万事大吉了,直到线上爆出一个内存泄漏,查了两天才发现是协程作用域没绑对。

为什么会这样?因为协程作用域如果不和组件的生命周期绑定,它就会一直活下去。你Activity都finish了,它还在后台等着BLE回调,那个Activity对象就永远回不了头。

⚠️ 核心认知: 协程不是银弹。它解决了回调嵌套的问题,但引入了作用域管理的新挑战。用不好,泄漏比回调时代还隐蔽。

1.3 泄漏的蝴蝶效应

咱们拆解一下泄漏是怎么发生的。其实链路很简单:

  1. 协程启动 —— 在Activity/Fragment里用 launch 启动了协程
  2. 作用域未绑定 —— 没有用 viewModelScope 或 lifecycleScope,而是用全局作用域
  3. BLE操作阻塞 —— 协程在等待BLE回调,一直挂起
  4. 组件销毁 —— 用户退出页面,但协程没取消
  5. 引用无法释放 —— 协程持有外部的引用,GC回收不了
  6. 内存泄漏 —— 页面实例越来越多,OOM只是时间问题

我在项目中遇到过这样一个案例:一个蓝牙扫描页面,用户来回进出几次,内存就飙到了200多MB。用MAT一分析,发现每个Activity实例都被协程的Continuation对象强引用着。说白了,就是协程没取消,把整个页面都"拽"住了。

💡 一个小数据: 单次泄漏大约占用 2-5 MB(含Bitmap等资源),用户进出20次页面,泄漏量就奔着100MB去了。OOM阈值一般是256MB,你算算能撑多久。

1.4 知识体系总览

这一章咱们要聊的东西,其实就围绕下面这张图展开。从左到右,从上到下,把"角色"和"挑战"讲透。

协程在BLE开发中的角色与挑战 —— 知识体系 协程在BLE开发中 的角色与挑战 BLE异步回调困境 回调嵌套 · 生命周期脆弱 协程结构化并发 suspend · 作用域管理 作用域泄漏风险 协程未取消 · 对象无法回收 泄漏排查实战 定位根因 · 修复与验证 最佳实践方案 作用域绑定 · 生命周期感知 课程核心:理解角色 · 掌握作用域 · 杜绝泄漏

这张图就是我们这一章要走的路。从左边的"痛点"出发,到右边的"方案",再到中间的"风险"——说白了,就是先看清问题,再理解协程怎么帮我们,最后警惕它带来的新坑。下半部分就是实战环节了:怎么排查、怎么修复、怎么形成最佳实践。

1.5 学完本章你能带走什么

这一章不是干讲理论,我会带着你从真实案例出发,一步步拆解。你学完能带走这几样东西:

  • 一套排查Ble泄漏的思维框架 —— 再遇到内存泄漏,知道从哪下手
  • 几个实战工具的使用技巧 —— MAT、LeakCanary、Dump具体怎么看
  • 协程作用域的正确绑定姿势 —— 什么场景用哪个Scope,门清
  • 一份避坑清单 —— 我踩过的那些坑,你不用再踩一遍

🎯 一句话总结本章: 协程是BLE开发的好帮手,但作用域管理搞不好,它会变成泄漏的源头。咱们这一章,就是把它的脾气摸透,让它乖乖听话。