{"version":"0.1.0","code":"0000","result":true,"message":"处理成功","errdetail":"","timestamp":1671508841817,"data":{"id":82500517,"title":"Android 怎么实现信号频率控制?","slug":"tk7qky","format":"lake","bookId":26046811,"body":null,"body_draft":null,"body_html":"
由于高德现有的后端融合算法对频率十分敏感,需要外部保证输入的信号是持续、稳定的,不能偏离预期太多(一般要求传感器信号频率为10Hz,丢帧率低于3‰)。
而一般 IMU 输出的传感器频率会大于10Hz,此时需要对信号进行降频。
Android 上有几种可选的方案,例如,Handler(postDelayed)、Timer(schedule/scheduleAtFixedRate) 。根据此前的项目适配经验,推荐使用 Timer.scheduleAtFixedRate。
Timer.scheduleAtFixedRate 会根据任务运行时间动态调节下次任务的触发时间,能够比较好的适应设备高负载下无法及时响应所导致信号不稳定问题。
但是原生的 Timer.scheduleAndFixRate 由于使用了 System.currentTime 这个与本地时间相关的函数,会受到本地时间修改的影响,造成定时器逻辑错乱。
需要自己重新实现一个 Timer.scheduleAtFixedRate ,用单调时钟时间 SystemClock.elapsedRealtime 替代 System.currentTime 。
CustomTimerTask.java 与原生的 TimerTask.java 一样。
CustomTimer.java 只是把原生 Timer.java 内 scheduleAtFixedRate 调用的 System.currentTime 修改成 SystemClock.elapsedRealtime 。
\uD83D\uDCCECustomTimerTask.java
如果系统存在类似会造成导航进程挂起的「休眠」设计,在使用上述方案时,需要额外对接系统休眠的广播,在进入休眠前注销定时器,并在休眠恢复后重新注册。否则,会引起 Timer.scheduleAtFixedRate 工作异常,休眠恢复后定时器会以超高频率触发来「补偿」休眠时间。
保险起见,每次收到启动信号的时候,都判断注销定时器后再启动,防止一些特殊原因导致定时器在休眠之前未正确注销的情况。例如,熄火但还未进入休眠时又点火了。
// 启动定时器\npublic void startTimer() {\n if (mTimer == null) {\n mTimer = new CustomTimer();\n }\n \n if (mTimerTask == null) {\n mTimerTask = new CustomTimerTask() {\n @override\n public void run() {\n //......\n }\n };\n }\n \n mTimer.scheduleAtFixedRate(mTimerTask, 0, 100);\n}\n\n// 注销定时器\npublic void cancelTimer() {\n if (mTimer != null) {\n mTimer.cancel();\n mTimer = null;\n }\n \n if (mTimerTask != null) {\n mTimerTask.cancel();\n mTimerTask = null;\n }\n}\n