26、WiFi唤醒与锁:WifiLock(WiFi锁)的使用场景、获取与释放WifiLock、避免电量浪费

做Android开发这么多年,WiFi锁(WifiLock)是我觉得最容易被忽视、但又特别关键的一个知识点。说白了,它就是用来防止WiFi模块在屏幕熄灭后自动休眠的机制。你想想看,如果你的App正在下载一个大文件,或者在做视频通话,结果屏幕一关WiFi就断了,那体验得多糟糕。

我早期做一款直播App时就踩过这个坑。用户反馈说“一锁屏就卡顿”,排查了半天才发现是WiFi在后台被系统休眠了。嗯,从那以后,我对WifiLock的使用就格外上心了。

什么是WifiLock?

WifiLock是Android系统提供的一种电源管理锁。它的作用很简单——强制保持WiFi无线电模块处于唤醒状态

系统默认的行为是:当屏幕熄灭后,如果一段时间没有网络活动,WiFi会进入低功耗模式甚至断开连接。这是为了省电。但有些场景下,我们需要WiFi持续工作,这时候就需要WifiLock出场了。

核心要点:WifiLock只控制WiFi模块的电源状态,不影响CPU休眠。如果需要同时保持CPU唤醒,还得配合WakeLock使用。

使用场景

我个人习惯把WifiLock的使用场景归纳为三类:

  • 大文件传输:比如下载APK、缓存视频、同步离线地图。这些操作通常需要持续几分钟甚至更久,屏幕熄灭后如果WiFi断了,下载就会失败。
  • 实时通信:VoIP通话、视频会议、在线游戏。这类场景对网络连续性要求极高,哪怕断个几秒都会影响体验。
  • 后台数据同步:邮件推送、IM消息接收、IoT设备状态上报。虽然现在有WorkManager和FCM,但某些定制化场景还是需要自己控制WiFi状态。

我在项目中遇到过一种特殊情况:某款平板设备在休眠后WiFi延迟特别高,ping值从10ms飙到500ms。后来发现是WiFi进入了省电模式。用WifiLock锁定后,问题就解决了。

WifiLock的类型

Android提供了几种不同级别的WifiLock,区别在于对WiFi模块的控制粒度:

类型 说明 适用场景
WIFI_MODE_FULL 保持WiFi全速运行,扫描也不间断 视频通话、在线游戏
WIFI_MODE_FULL_HIGH_PERF 全速模式 + 高性能,功耗更高 低延迟要求的场景
WIFI_MODE_SCAN_ONLY 只保持WiFi扫描,不保持连接 位置服务、WiFi扫描

说实话,大部分场景用WIFI_MODE_FULL就够了。高性能模式我很少用,除非是做竞技类游戏或者实时音视频处理。

获取与释放WifiLock

使用WifiLock的流程其实很简单,但细节决定成败。来看代码:

// 1. 获取WifiManager实例
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);

// 2. 创建WifiLock
WifiManager.WifiLock wifiLock = wifiManager.createWifiLock(
    WifiManager.WIFI_MODE_FULL, 
    "my_app:wifi_lock_tag"
);

// 3. 获取锁
wifiLock.acquire();

// 4. 业务操作(下载、传输等)
doNetworkOperation();

// 5. 释放锁
wifiLock.release();

嗯,这里要注意几个坑:

  • 必须成对出现:acquire和release要一一对应。多release会抛异常,少release会导致WiFi一直唤醒,耗电严重。
  • 生命周期管理:我建议在onStart/onResume中acquire,在onStop/onPause中release。千万别在onCreate里acquire然后忘了释放。
  • 检查是否已持有:可以用wifiLock.isHeld()来判断当前锁状态,避免重复获取。

警告:千万不要在UI线程中长时间持有WifiLock!如果必须长时间保持,请使用前台服务(Foreground Service)并配合通知提醒用户。否则会被系统判定为耗电应用,甚至被强制杀死。

避免电量浪费

WifiLock是一把双刃剑。用好了提升体验,用不好就是电老虎。我见过有些App一启动就acquire WifiLock,直到退出才release。这其实很粗暴。

我的建议是:

  1. 按需获取,用完即放:只在真正需要的时候acquire,操作完成后立即release。比如下载文件时,可以在开始下载前acquire,下载完成后release。
  2. 使用超时机制:如果业务逻辑复杂,可以设置一个最大持有时间。比如:
// 设置10秒超时,防止忘记释放
wifiLock.acquire(10000);
  1. 监听屏幕状态:如果屏幕亮着,其实不需要WifiLock。可以结合屏幕状态监听来动态管理锁的获取与释放。
  2. 使用WorkManager替代:对于后台同步任务,优先考虑WorkManager。它内部已经处理好了WiFi和CPU的唤醒逻辑。

小技巧:在调试阶段,可以用adb shell dumpsys wifi查看当前WifiLock的持有情况。如果发现某个锁长时间未释放,那就是需要优化的地方。

知识体系图

下面这张图梳理了WifiLock的核心逻辑,从使用场景到获取释放,再到电量优化,一目了然:

WifiLock 知识体系 WifiLock 使用场景 大文件传输 实时通信 后台数据同步 获取与释放 createWifiLock() acquire() / release() 生命周期管理 避免电量浪费 按需获取,用完即放 设置超时机制 监听屏幕状态 核心原则:用则取,用完放,不滥用

最后说一句,WifiLock本身不是洪水猛兽。只要遵循“用则取,用完放,不滥用”的原则,它就是你提升用户体验的利器。我在项目里见过太多因为忘记释放WifiLock导致的耗电问题,也见过因为不敢用WifiLock导致功能体验差的案例。把握好这个度,才是真功夫。

公众号:蓝海资料掘金营,微信deep3321