ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Android 个人健康管理系统实战:从数据采集到打包上线

Android 个人健康管理系统实战:从数据采集到打包上线 做这个项目之前我把市面上主流的健康类应用几乎都装了一遍。说实话小米健康、华为运动健康这些产品在自家生态里体验确实不错但一旦涉及数据导出、跨平台同步、自定义提醒或者想把健康数据和自己写的其他工具打通就会碰到各种无形的墙。这也是我决定在Android平台上做一套个人健康管理系统的最直接原因。这套系统不是要跟大厂的软件比功能完整度而是解决一个很实际的需求把手机传感器、蓝牙外设、手动录入这三类数据源统一收口形成一套本地优先、可自由扩展的个人健康档案。如果你也正在用Android Studio做类似的健康管理项目或者正准备从零开始写一个带数据采集、图表展示、后台提醒的App这篇文章里涉及的架构取舍、权限坑、存储适配和打包流程应该能帮你少走不少弯路。1. 为什么自研个人健康管理系统而不是直接用人家的1.1 现成App的两个硬伤先说最明显的问题封闭性。大厂健康App的数据模型完全围绕自家生态设计你戴的是别家手环或者你想记录的数据项不在它预设的维度里录入流程就变得很别扭。我试过在几个主流健康App里手动记录每周腰围变化有的产品压根没有这个入口有的录进去之后只能看趋势图没法导出原始数值。对于像我这种喜欢做季度健康复盘的人这种数据黑洞非常致命。另一个问题是权限和后台的隐性消耗。为了保持每天N分钟之类的推送这些App往往常驻后台还申请了大量和核心功能不太相关的权限。我同事的手机上某个健康App光定位权限就申请了三个级别但实际我只是用它看步数。权限多意味着每次系统升级都可能出幺蛾子也意味着隐私风险面被放大。自己做系统权限清单可以精确到每一行都能解释清楚是干什么用的。1.2 这个项目的目标和边界我给自己定的目标是做一个单机优先的健康管理系统核心就三件事数据采集手机计步传感器、蓝牙心率/血氧设备、手动录入。数据管理本地SQLite存储支持数据项的增删改查和周期汇总。可视化首页展示今日步数、心率曲线、体重趋势并对异常数据做简单提醒。边界也很明确不做云端同步、不做社交、不做复杂的数据分析模型。因为这些功能会指数级增加开发和维护成本而且数据留在本地反而更符合个人管理系统的定位。技术上我选用纯原生Android开发框架层面只引入Jetpack组件热词里经常刷到的Android framework相关底层源码只在我需要排查系统级行为时才去翻平时不碰。2. 健康数据的采收入口传感器、蓝牙设备和手动兜底2.1 计步数据Activity Recognition的取舍计步是健康管理的基础数据。Android设备获取步数有两条常规路径我用了一个星期的时间分别做了验证。第一条路径是直接注册TYPE_STEP_COUNTER传感器。这是硬件级计步耗电极低API 19之后就提供原理是芯片内部维护了一个从开机以来的累计步数计数器。代码很简单SensorManager manager (SensorManager) getSystemService(Context.SENSOR_SERVICE); Sensor stepCounter manager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER); manager.registerListener(this, stepCounter, SensorManager.SENSOR_DELAY_UI);注册之后在onSensorChanged里拿到的values[0]就是从手机开机开始的累计步数。这里有一个特别容易错的地方这个数值不是今日步数是开机累计值。如果你要展示今天的步数必须在每次开机后记一个基线值然后用当前值减去基线值。我最初直接拿这个值去渲染进度条结果发现重启手机后步数瞬间变成几千步排查了半天才发现是基线没处理好。第二条路径是ActivityRecognitionClient它结合加速度计和陀螺仪识别走路、跑步、骑车等行为事件反过来推算活动量。它的优点是能区分运动类型缺点是需要随时申请ACTIVITY_RECOGNITION权限而且事件的实时性和准确性在不同机型上差别很大。实测下来小米某些机型识别骑车事件滞后十几秒华为部分机型在没有传感器校准的情况下误报频率高。考虑到这个项目以每日总量为核心指标我最终选了TYPE_STEP_COUNTER为主、ActivityRecognition为辅的方案后者只用来判断当前是否处于运动状态用于决定是否加大数据采样频率。2.2 心率等体征BLE外设连接心率数据光靠手机是不行的手环或心率带是必备的外设。这里用的就是Android蓝牙的BLE方案核心链路是扫描、连接、发现服务、订阅特征值。扫描时有个坑是Android 12之后必须有BLUETOOTH_SCAN权限否则连接流程直接卡死。而且扫描回调里拿到的BluetoothDevice对象别急着存引用最好是只保存MAC地址因为该对象可能随时失效。连接后通过BluetoothGattCallback回调里拿到心率服务Heart Rate Service (0x180D)的Heart Rate Measurement (0x2A37)特征然后调用setCharacteristicNotification(characteristic, true)再给该特征设置descriptor写入打开通知才能收到心率数据的实时推送。实时心率值按照BLE协议第一个字节的高位bit决定了心率值格式是UINT8还是UINT16。我在协议解析上栽过一跤某品牌的廉价手环返回的数据格式和标准文档不完全一致它把第0字节直接当心率值返回导致界面一度显示心率四百多。后来加了一层数据合理性校验心率范围在30~220之外的值直接丢弃这个问题才算彻底解决。外设连接的耗电不可忽视我的做法是只在用户停留在测量页面时才主动扫描和连接一旦页面销毁就断开Gatt连接。不要试图在后台长连手环一来厂商限制多二来对手机续航影响明显后台只保留昨天的步数汇总和待办提醒就够了。2.3 手动录入血压、血糖和腰围最后一块是手动录入。虽然智能设备能覆盖步数和心率但血压、血糖、腰围这类数据绝大多数人还是靠手动记录。我在录入页面设计了一个快捷模板功能每种指标对应不同的输入字段。血压模板包含收缩压、舒张压、心率三个字段因为电子血压计测出来的心率可以和脉搏联系在一起血糖模板除了血糖值还必须选餐前/餐后和测量时间餐后两小时和空腹的血糖参考区间完全不一样腰围模板就一个值加一个备注。每个模板在保存时会写入一个数据源字段标记为manual这样在统计页面可以单独筛选哪些数据是设备测的、哪些是手填的避免混合统计导致趋势失真。手动录入最容易忽略的问题是时区。如果用户晚上十二点半测完体重并保存这条记录可能因为日期字段处理不当归到前一天。我统一使用LocalDate而不是Date去定义业务日期即用户感知的日期以他所在时区的零点为准这样无论存储还是聚合都不会出现偏移。3. 数据层的设计从建表到聚合3.1 选型Room DataStore为什么不用其他方案数据存储这块我首选的是Jetpack的Room理由很直接它把SQLite的复杂度封装得刚好编译期校验SQL还能跟LiveData和Flow配合实现响应式UI。SQLite数据库文件就在本地不依赖网络完全符合数据留在自己手里的定位。有人可能会问为什么要选Room而不直接上GreenDAO或者用文件存储。Docker容器、Realm这些框架我也用过但对于一周只能抽几个晚上写代码的独立开发者来说Room的学习成本和调试成本是最低的。它生成的数据库文件后缀是.db直接用SQLite浏览器就能打开排查问题这一点在我开发后期查数据错乱的时候帮了大忙。共享偏好这块我没有用原生SharedPreferences改用了Jetpack DataStore的Preferences版本。理由是SharedPreferences的apply和commit机制在跨进程读写时会偶发ANR而DataStore基于协程和Flow天然支持异步读取也不会阻塞UI线程。项目里几乎没有跨进程需求但DataStore的响应式特性让设置项的修改能即时反映到多个界面体验好很多。3.2 健康记录表的结构核心表只有四张每张都不复杂但字段设计上特意考虑了几个细节。第一张是daily_summary存放每天汇总的统计值比如总步数、活跃时长、睡眠时长。主键就是日期这样查询某一天的数据只有一行性能非常好。有个技巧是把数据源字段直接冗余在这里比如今天是小米手环测的步数还是手机传感器测的步数这会影响后续数据的可比性。第二张是health_metric_record存用户输入的每一项具体指标。字段包括指标类型weight、blood_pressure、blood_glucose、waist、数值、单位、测量时间、备注。为什么不用一张宽表即一个字段对应一个指标因为健康指标的维度会不断扩展今天记录血压明天可能想记录体温、体脂率宽表改一次结构要清一次数据窄表加一行数据就行了。第三张是alert_rule定义异常提醒规则比如心率超过120提醒、血糖超过7.0提醒。第四张是alert_log记录提醒触发历史和用户是否已查看。后两张表在项目早期用不上但提醒功能几乎是健康管理App的标配先把模型建好后面做功能时只需要写业务逻辑不用再动数据库结构。3.3 数据聚合与过期清理健康数据的聚合是个长期问题。我拿到的原始数据是有粒度的比如此刻走了一步、心率值每分钟一个点。但UI和统计根本不需要这么高的粒度而且数据只增不减会让数据库越来越大。我的解决方案是两层聚合。第一层聚合发生在写入时心率数据按分钟聚合把一分钟内采集到的所有心率值取平均丢弃原始瞬时值步数数据按小时聚合每小时记一个累计值。之所以按小时而不是按天聚合是因为保留小时粒度还能画出一天的走势图但如果保存到天粒度走势图就失真了。第二层聚合是定期迁移。每周跑一次定时任务把超过三十天的分钟级聚合数据再压缩成天级聚合分钟级原数据删除。压缩后的当天代表值是最大值、最小值、平均值三项。这样数据库体积大概率能控制在几十MB内查询压力也很小。这个机制的可靠性非常关键我用WorkManager的PeriodicWorkRequest实现每天凌晨执行一次压缩清理。WorkManager是Android官方推荐的定期任务方案比我自己开Handler线程轮询稳定得多它会根据系统状态自动选择合适的执行时机而且设备重启后任务还能恢复执行。4. 权限申请、后台任务与厂商限制踩坑最重的一个环节4.1 权限清单与动态申请健康管理App需要的权限我整理成了下面这张表每项都写了用途方便对照检查自己项目的AndroidManifest.xml权限用途是否必须备注ACTIVITY_RECOGNITION计步传感器与运动状态识别是Android 10起必须运行时申请BODY_SENSORS读取心率、血氧等传感器数据是Android 12起新增BODY_SENSORS_BACKGROUNDBLUETOOTH_SCAN扫描BLE外设是Android 12起新增BLUETOOTH_CONNECT连接BLE外设是Android 12起新增POST_NOTIFICATIONS发送每日健康提醒通知是Android 13起必须运行时申请FOREGROUND_SERVICE前台服务保活视情况Android 14要求声明前台服务类型RECEIVE_BOOT_COMPLETED开机后重启定时任务建议在Manifest注册BootReceiver动态申请权限的代码网上到处都有我就不贴完整代码了但有几个细节必须强调。第一ACTIVITY_RECOGNITION权限弹窗的文案是系统定的开发者没法修改如果你在弹窗前没有给用户做预热说明很多人会误以为这是一个入侵性权限而拒绝掉。我在申请前会先弹一个自定义对话框解释需要识别走路状态来统计步数用户点了确认再发起系统权限请求这样授权率明显提升。第二BODY_SENSORS在Android 12之前是普通权限直接安装就给了Android 12之后变成运行时权限。如果你的项目compileSdk升级到了31以上但代码里没有对它做运行时申请在新版本手机上心率功能会静默失效没有任何报错弹窗。这类静默失效问题是升级SDK后最容易踩的坑。4.2 前台服务与WorkManager的配合采集健康数据需要后台运行这里有两条路一是起一个前台服务Foreground Service二是用WorkManager做周期性任务。很多初学者喜欢用前台服务把所有事情都干了结果就是通知栏永远挂着一个图标用户烦应用市场审核也可能以常驻通知无法关闭为由拒审。我的分工思路是实时数据采集走前台服务比如用户正在测量心率或记录跑步轨迹这时候前台服务是合理的日常的步数统计、数据清理、提醒同步全部走WorkManager。WorkManager最适合做不一定需要立刻执行、但需要在合适时机执行的任务比如每天凌晨两点清理数据、在用户下次解锁时同步一次昨天的手环数据。它的底层会根据系统空闲窗口调度既省电又不容易被系统判为后台滥用。Android 14之后前台服务必须在Manifest里明确声明类型比如foregroundServiceTypehealth或connectedDevice并且运行时需要FOREGROUND_SERVICE_HEALTH这类权限。这个变化影响很大如果不声明类型服务起不来或者直接被SecurityException。我升级到Android 14模拟器测试时所有前台服务相关代码都炸了一遍就是因为没加foregroundServiceType声明。4.3 厂商后台限制华米OV的启动管理这一节是我个人最想吐槽的部分。原生Android的后台机制是一套标准但是国内厂商普遍会对第三方应用做启动管理限制。你的应用就算在设置里开了所有权限如果用户没有在应用启动管理里把允许自启动和允许关联启动打开闹钟式的定时任务照样不执行。我在华为设备上遇到的一个具体案例是WorkManager的PeriodicWorkRequest设置了每12小时同步一次手环数据但是在华为手机上如果用户杀过应用进程之后WorkManager永远不会被触发除非用户手动打开应用。原因就是华为的App启动管理把WorkManager的AlarmManager通知给屏蔽了。后来我处理的办法是在引导页加了一个开启开机自启动的引导步骤同时在应用内部检测任务是否被系统停用检测到异常就直接提示用户手动调整厂商设置。这不是什么高深的解决方案但提醒文案写清楚了用户的配合度会高很多。另外申请RECEIVE_BOOT_COMPLETED权限后一定要在Manifest里注册一个BroadcastReceiver在onReceive里重新调用WorkManager.getInstance(context).enqueue把周期性任务再入队一次。因为手机重启后之前注册的任务虽然是持久化的但部分厂商系统下任务不一定能恢复执行保险起见重新入队没有副作用因为WorkManager会去重。4.4 fileprovider与分区存储带来的路径问题健康管理系统免不了导出数据或者备份数据库这里就撞上了两个紧俏问题FileProvider和分区存储。Android 7.0以后应用之间共享文件不能直接用file://URI必须用FileProvider生成content://URI。我最初导出健康数据做分享时直接用Uri.fromFile(file)结果所有目标应用都抛FileUriExposedException。后来改成了这样provider android:nameandroidx.core.content.FileProvider android:authoritiescom.example.health.fileprovider android:exportedfalse android:grantUriPermissionstrue meta-data android:nameandroid.support.FILE_PROVIDER_PATHS android:resourcexml/file_paths / /provider然后生成URI时调用FileProvider.getUriForFile(context, com.example.health.fileprovider, file)同时给目标Intent添加FLAG_GRANT_READ_URI_PERMISSION。这套流程大概半小时就能搞定但完全不了解的人会折腾很久。分区存储的问题更隐蔽。Android 11之后强制分区存储应用不能随意访问公共目录下的任意文件只能访问自己关联目录和用户主动选择的文件。很多人的数据库备份导出到Download目录然后用文件管理器去复制明明能看到文件但迁移到新手机后数据却没有了——因为备份文件压根没写成功只是写入到了应用的私有外部目录里。我采用的做法是备份文件统一写到getExternalFilesDir(null)下的backup目录这个目录不需要额外权限应用卸载时会一并清理但用户可以用系统文件管理器移动到其他位置。需要导出到公共目录时用Intent触发系统的ACTION_CREATE_DOCUMENT让用户选择保存位置系统会返回一个可写的URI这时候再往里面写入数据就不会触碰分区存储的限制。这两个API的差别我认为值得每个Android开发者记住。5. 首页可视化协调布局、环形进度条与动态图表5.1 协调布局和Banner的首页结构首页我用了CoordinatorLayout AppBarLayout banner的结构这是Android开发里非常经典的一个组合。CoordinatorLayout负责协调子View之间的嵌套滚动事件AppBarLayout承载顶部工具栏并支持折叠/展开动画banner则是健康日报的轮播卡片。这种结构在健康类App里几乎成了事实标准因为我需要让用户在一屏内看到今日步数、平均心率、最新体重三个核心指标同时还能通过横向滑动查看最近七天的健康日报卡片。将banner放在AppBarLayout下方的折叠区域里随着列表上滑会自然被顶出去这样既保证了信息密度又不会让首屏内容过于拥挤。协调布局有一个坑如果直接在AppBarLayout里放一个Toolbar和RecyclerView的嵌套滚动默认情况下RecyclerView是不会触发折叠动画的。必须在布局里给RecyclerView设置app:layout_behaviorstring/appbar_scrolling_view_behavior。很多初学者漏掉这一行然后来问为什么页面滑动没反应问题就出在这。5.2 环形进度条不是贴图是自定义View今日步数达到目标的百分比我选择了环形进度条的展示方式这也是很多运动App的标配。实现方式有两种一种是直接拿一张半圆环PNG图改角度另一种是自定义View用Canvas画。前者虽然快但图片资源在不同分辨率手机下会糊而且无法做动画过渡后者代码量不大效果更好。核心逻辑就是onDraw里画两层圆弧底层是灰色轨道上层是彩色进度弧再用SweepGradient给进度弧加渐变效果。进度动画我用了ValueAnimator监听动画值变化调用invalidate()重绘这样每次进入页面时进度条有从0到目标值滚动生长的效果而不是生硬地跳到最终状态。这里有个细节动画时长设定在800毫秒到1200毫秒之间比较合适太短用户看不清变化太长会让人觉得卡顿。这个进度条组件我没有采用第三方库因为总共也就一百多行代码自己写的还能完全控制交互逻辑。比如点击环形进度条中心区域可以切换展示步数目标完成率和久坐提醒倒计时两种模式这种自定义交互如果依赖第三方库往往得做一大堆配置和回调反而不如自己写省事。5.3 折线趋势图的数据交互折线趋势图用来自定义View绘制主要展示近三十天体重或心率的变化趋势。这个图表的实现有几个关键点X轴时间标签采用等距分布不按真实日期间隔因为健康数据会出现断档比如某几天没测心率如果按真实时间间隔画折线会断成好几段视觉很难看按等距画则可以保留连续感并把断档日期在数据点上做标识。Y轴范围固定在数据极值基础上上下扩展百分之十避免图形顶到边框。触摸点时通过onTouchEvent命中检测找到最近的数据点弹出浮层显示当天的具体数值和备注。开发里最容易被忽视的是坐标系的转换。Canvas的小数点和像素坐标谁都会设置但要真正把数据值换算成像素坐标还需要考虑view的padding。我见过一个项目图表边缘线总是比预期多出一个像素的偏移排查了一圈发现是因为getWidth()返回的是包含padding的总宽度而绘图中心没有减去padding值。这种几个像素的误差在1080P的屏幕上肉眼几乎看不见但叠加到数据点上触摸命中区域就会偏移。5.4 九宫格入口与动态图标主题首页下方我设置了九宫格快捷入口用来导航到心率测量睡眠记录饮食打卡报告导出等功能页面。九宫格这种布局在工具类App里虽然传统但确实简洁直观尤其是功能模块比较多的时候比抽屉菜单更符合移动端单手操作的习惯。实现时用GridLayoutManager RecyclerView每个item就是一个带图标和文字的Card。为了让页面不死板我做了动态主题图标的颜色不是固定写死的而是根据当前最高优先级指标的健康状态来变。比如今天步数达标运动图标就是绿色如果心率的当日平均值高于正常区间心率图标就成了黄色提醒色。这个动态图标主题功能本质就是图标资源的动态切换通过setColorFilter给VectorDrawable染色来实现不额外增加图片资源体积。这里提一个VectorDrawable适配上的经验如果目标机型低于Android 5.0使用VectorDrawable需要开启支持向量图标的开关在build.gradle里加vectorDrawables.useSupportLibrary true否则部分系统组件无法正常渲染图标。我一开始没加这个配置在Android 4.4的旧设备上测九宫格图标全部不显示排查了半天才发现是这行配置的问题。6. Android Studio下的完整打包链路6.1 开发环境的搭建与中文设置我自己用的是Android Studio最新稳定版从google官网下载安装包Windows环境需要先装JDK 17以上。这里给新手一个建议安装Android Studio时SDK路径不要选包含中文或空格的目录虽然现在大部分情况也能跑但某些原生编译工具链会出奇怪的问题。我从Android SDK官网下载的commandline-tools和platform-tools目录解压路径也尽量保持全英文。Android Studio默认是英文界面要改成中文需要通过Plugins插件市场安装中文语言包。我一开始用着英文界面还行帮同事配置环境时他说中文语言包装不上最后发现是Proxy设置问题。如果你也在国内网络环境下装插件需要在Settings里把自动检测网络代理打开或者手动指定代理。这个和Studio版本无关是插件商店访问网络的问题。6.2 从项目工程到APK的完整打包流程打包APK分Debug和Release两种。Debug包是纯开发调试用直接点击Run按钮就能装到手机上。Release包需要签名步骤是Build菜单 - Generate Signed Bundle / APK - 选择APK - 创建或选择签名文件。签名文件是.jks文件密码一定要记住这个文件一旦丢失意味着以后无法再对应用进行升级覆盖安装只能卸载重装。我见过一个团队因为签名文件丢失应用评分被差评轰炸就是因为用户升级时会报签名冲突。如果你是拿到别人的Android Studio项目源码想在自己的机器上编译出APK关键的流程是用Android Studio打开项目根目录的build.gradle。等待Gradle同步完成这个过程会下载依赖耗时会比较长取决于网络状况。在Build Variants面板选择debug或release构建变体。点击Run按钮IDE会自动完成编译、打包、签名debug包用默认debug签名并安装到你连接的测试设备上。有个移植项目时很常见的坑原作者用的compileSdk、minsdk版本和本机SDK版本不匹配或者依赖库版本在网络上已经拉取不到。解决方法是把build.gradle里的版本号改成自己能获取到的版本或者开启offline mode用本地缓存的依赖。如果源码里带了完整的gradle wrapper一般会处理好这个问题。6.3 多机型适配与版本差异健康管理App往往需要在用户手上的多种Android设备上跑我维护的老旧设备从Android 8到Android 15都有。适配工作主要集中在这几个方面屏幕适配方面我使用ConstraintLayout配合dp单位同时给不同尺寸的设备设置不同的gapFrom间距关键数值用dimens.xml限定避免小屏手机上按钮和图表挤压在一起。此外还要注意折叠屏和Pad的宽屏适配健康数据和图表在这种大屏上有更多展示空间不合理利用会导致页面两侧大片空白。系统版本差异方面Android 10之前和之后的存储访问方式彻底不同这是适配工作的重点。我在应用内所有涉及文件读写的地方都封装了一个FileRepository内部通过Build.VERSION.SDK_INT判断走哪套逻辑上层业务代码从来不需要关心当前运行的是哪个系统版本。这种封装方式对于老系统和新系统的兼容性维护非常省心。还有个容易被忽略的适配点是通知渠道。Android 8.0之后的每个通知都必须绑定一个NotificationChannel否则通知直接不显示。健康提醒类的通知我建了channel_health_reminder紧急异常提醒单独建了channel_health_alert并设置高优先级这样用户可以在系统设置里分别控制两类通知的开关体验更细致。6.4 日志定位从崩溃堆栈到数据排查开发过程中日志定位是我花时间最多的事情也是最有价值的一步。不要再用System.out.println打点了统一用Log组件按tag区分模块。崩溃堆栈定位相对简单最考验人的是逻辑错误。我举个例子。一次用户反馈昨天明明走了两万步第二天打开App显示只有八千。我第一反应是数据写入时序出了问题。因为应用在后台时步数传感器的回调是持续不断的我把累加逻辑放在了onSensorChanged里每次values[0]和基线的差值上但忘记考虑传感器在设备重启后的基线重置。设备重启后步数计数器会从零重新开始累加如果数据库里保存的基线值还是开机前的值那计算出来的当日步数就会突然变成一个很大的数甚至归零。排查这类型的问题我用的办法是在App里加了一个开发模式菜单点一下可以导出一份调试日志包含传感器回调时间戳、累加值、数据库写入记录。拿到日志后对照设备的真实重启时间和数据写入时间问题就非常直观了。我特别推荐在做这类硬件传感器相关项目时保留一个调试日志模块它能帮你把玄学问题变成可以复现的bug。至于网上经常有人分享的content://com.mi.health/files/log/xiaomifit.main.log这类路径其实就是小米健康App调试日志的位置。你可以在设备上看到第三方App的私有目录内容前提是你的Android设备已经root或者开启了开发者选项里的通过USB安装应用权限否则这些日志是拿不到的。这个思路反过来也提醒我自己的App日志要写到应用私有目录不要写到公共存储否则别的应用和用户都能轻易看到敏感健康数据。从需求分析到编码实现这套系统前前后后我写了差不多一个半月。这中间重写最多次的模块不是UI不是图表而是后台任务的调度策略。Android的后台机制一直在收紧每一代系统都在砍应用后台常驻能力而健康管理App恰恰需要长期在后台采集数据。我最后确定的方案并不复杂前台服务只负责用户主动使用期间的采集周期性的数据汇总和清理全部交给WorkManager绝不尝试做永不被杀这类对抗系统的事情。因为你越跟系统对着干系统就越狠地限制你最后受苦的还是用户。这个项目做完以后我最深的体会是所谓个人健康管理系统技术门槛并不高难的是把数据来源、存储、展示、后台调度这条链条上的每一个环节都理顺任何一种数据源断掉、任何一次任务不执行都会让数据变得不可信。而数据一旦不可信整个系统的价值就归零了。所以如果你也正打算做类似的工具优先把数据稳定性和权限适配做扎实UI和动画反而是最容易往后放的部分。
返回列表