Google Fit API计步问题:如何获取当日步数而非累计总步数
嘿,我看到你现在在用Google Fit API开发时遇到了一个小问题——当前代码返回的是累计总步数,但你需要的是当日的步数。咱们来一步步把这个问题搞定!
问题分析
你当前的代码用的是DataType.TYPE_STEP_COUNT_CUMULATIVE(累计步数)结合Sensors API来监听数据,这个API的作用是实时推送设备从开始记录以来的总累计步数,所以每次回调得到的都是从设备激活至今的总步数,自然不是你想要的当日数据。
要获取当日步数,咱们需要用到Google Fit的History API,它可以帮我们查询指定时间范围内的步数统计,或者直接调用官方提供的便捷方法获取当日总步数。
解决方案步骤
1. 更新GoogleApiClient配置
首先,我们需要在GoogleApiClient的构建中添加History API的支持,同时调整权限(如果只需要读取步数,用FITNESS_ACTIVITY_READ更严谨):
mApiClient = GoogleApiClient.Builder(this) .addApi(Fitness.SENSORS_API) .addApi(Fitness.HISTORY_API) // 新增History API支持 .addScope(Scope(Scopes.FITNESS_ACTIVITY_READ)) // 仅读取权限即可 .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build()
2. 编写获取当日步数的方法
这里提供两种方式,你可以根据需求选择:
方式一:使用官方便捷方法readDailyTotal
这个方法会直接帮你计算当日的总步数,代码非常简洁:
private fun fetchDailySteps() { Fitness.HistoryApi.readDailyTotal(mApiClient, DataType.TYPE_STEP_COUNT_DELTA) .setResultCallback { dataReadResult -> if (dataReadResult.isSuccess) { // 获取当日总步数,没有数据则为0 val dailySteps = dataReadResult.total?.toInt() ?: 0 runOnUiThread { Toast.makeText(applicationContext, "当日步数: $dailySteps", Toast.LENGTH_LONG).show() } } else { Log.e("GoogleFit", "读取步数失败: ${dataReadResult.status.statusMessage}") } } }
方式二:自定义时间范围查询
如果你需要更灵活的时间范围(比如查询本周、昨天的步数),可以用这种方式手动指定时间段:
private fun fetchDailySteps() { // 获取当日0点到当前时间的时间戳(UTC时区,避免时区问题) val calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")) val endTime = calendar.timeInMillis calendar.set(Calendar.HOUR_OF_DAY, 0) calendar.set(Calendar.MINUTE, 0) calendar.set(Calendar.SECOND, 0) val startTime = calendar.timeInMillis // 构建读取请求,聚合当日的步数增量 val readRequest = DataReadRequest.Builder() .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA) .bucketByTime(1, TimeUnit.DAYS) // 按天分组 .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS) .build() Fitness.HistoryApi.readData(mApiClient, readRequest) .setResultCallback { dataReadResult -> if (dataReadResult.isSuccess) { var dailySteps = 0 // 遍历分组数据,累加步数 if (dataReadResult.buckets.isNotEmpty()) { for (bucket in dataReadResult.buckets) { for (dataSet in bucket.dataSets) { for (dataPoint in dataSet.dataPoints) { for (field in dataPoint.dataType.fields) { dailySteps += dataPoint.getValue(field).asInt() } } } } } runOnUiThread { Toast.makeText(applicationContext, "当日步数: $dailySteps", Toast.LENGTH_LONG).show() } } else { Log.e("GoogleFit", "读取步数失败: ${dataReadResult.status.statusMessage}") } } }
3. 在连接成功后调用方法
在onConnected回调里,调用我们刚写的fetchDailySteps()方法,这样客户端连接成功后就会自动获取当日步数:
override fun onConnected(bundle: Bundle?) { // 如果你还需要实时监听累计步数,可以保留原来的Sensors API代码 val dataSourceRequest = DataSourcesRequest.Builder() .setDataTypes(DataType.TYPE_STEP_COUNT_CUMULATIVE) .setDataSourceTypes(DataSource.TYPE_RAW) .build() val dataSourcesResultCallback = ResultCallback<DataSourcesResult> { dataSourcesResult -> for (dataSource in dataSourcesResult.dataSources) { if (DataType.TYPE_STEP_COUNT_CUMULATIVE == dataSource.dataType) { registerFitnessDataListener( dataSource, DataType.TYPE_STEP_COUNT_CUMULATIVE ) } } } Fitness.SensorsApi.findDataSources(mApiClient, dataSourceRequest) .setResultCallback(dataSourcesResultCallback) // 调用获取当日步数的方法 fetchDailySteps() }
4. 权限注意事项
别忘了在AndroidManifest.xml中添加必要的权限,并且在Android 10及以上系统中动态申请ACTIVITY_RECOGNITION权限:
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
额外提示
如果你想要实时更新当日步数,也可以结合Sensors API的累计步数:记录连接成功时的初始累计步数,之后每次onDataPoint回调时,用当前累计步数减去初始值,得到当日的实时步数。不过这种方法不如History API可靠,因为如果设备重启或者数据同步异常,初始值可能会不准确,所以更推荐用History API定期查询。
内容的提问来源于stack exchange,提问作者Joglidzee

