Android集成Google Fit后,如何获取步数计数器的定时更新回调?
看起来你已经搞定了Google Fit的基础集成,接下来要实现通过PendingIntent获取步数更新的定时回调,把数据同步到服务器对吧?我来一步步帮你完成这个需求:
实现步数更新的PendingIntent回调步骤
1. 编写接收更新的BroadcastReceiver
首先得创建一个BroadcastReceiver子类,用来接收Google Fit推送的步数更新广播,在里面处理数据获取和上传服务器的逻辑:
public class StepUpdateReceiver extends BroadcastReceiver { private static final String TAG = "StepUpdateReceiver"; // 注意:这里要确保mGoogleApiClient是可用的,你可以通过全局引用或者在Receiver里重新初始化 private GoogleApiClient mGoogleApiClient; @Override public void onReceive(Context context, Intent intent) { if (Fitness.ACTION_DATA_AVAILABLE.equals(intent.getAction())) { // 初始化GoogleApiClient(如果之前没保持连接的话) initGoogleApiClient(context); if (mGoogleApiClient.isConnected()) { fetchLatestStepData(); } else { mGoogleApiClient.connect(); } } } private void initGoogleApiClient(Context context) { if (mGoogleApiClient == null) { mGoogleApiClient = new GoogleApiClient.Builder(context) .addApi(Fitness.HISTORY_API) .addScope(new Scope(Scopes.FITNESS_BODY_READ_WRITE)) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(@Nullable Bundle bundle) { fetchLatestStepData(); } @Override public void onConnectionSuspended(int i) { Log.w(TAG, "GoogleApiClient suspended"); } }) .addOnConnectionFailedListener(connectionResult -> Log.e(TAG, "GoogleApiClient connection failed: " + connectionResult.getErrorMessage())) .build(); } } private void fetchLatestStepData() { // 获取最近24小时的步数数据,你可以根据需求调整时间范围 Calendar cal = Calendar.getInstance(); long endTime = cal.getTimeInMillis(); cal.add(Calendar.DAY_OF_YEAR, -1); long startTime = cal.getTimeInMillis(); DataReadRequest readRequest = new DataReadRequest.Builder() .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA) .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS) .bucketByTime(1, TimeUnit.HOURS) // 按小时分桶统计,可按需修改 .build(); Fitness.HistoryApi.readData(mGoogleApiClient, readRequest) .setResultCallback(dataReadResult -> { if (dataReadResult.getStatus().isSuccess()) { int totalSteps = calculateTotalSteps(dataReadResult); Log.d(TAG, "获取到的总步数:" + totalSteps); // 调用你的服务器接口上传数据 uploadStepsToServer(totalSteps); } else { Log.e(TAG, "读取步数数据失败:" + dataReadResult.getStatus().getMessage()); } // 用完后断开连接,避免资源占用 if (mGoogleApiClient.isConnected()) { mGoogleApiClient.disconnect(); } }); } private int calculateTotalSteps(DataReadResult result) { int total = 0; // 处理分桶数据 if (!result.getBuckets().isEmpty()) { for (Bucket bucket : result.getBuckets()) { for (DataSet dataSet : bucket.getDataSets()) { total += sumDataSet(dataSet); } } } else { // 处理直接返回的数据集 for (DataSet dataSet : result.getDataSets()) { total += sumDataSet(dataSet); } } return total; } private int sumDataSet(DataSet dataSet) { int sum = 0; for (DataPoint dp : dataSet.getDataPoints()) { for (Field field : dp.getDataType().getFields()) { sum += dp.getValue(field).asInt(); } } return sum; } private void uploadStepsToServer(int steps) { // 这里实现你的服务器上传逻辑,比如用Retrofit/OkHttp发送请求 // 示例伪代码: // ApiService service = RetrofitClient.getInstance().create(ApiService.class); // Call<Void> call = service.uploadUserSteps(steps); // call.enqueue(new Callback<Void>() { // @Override // public void onResponse(Call<Void> call, Response<Void> response) { // if (response.isSuccessful()) { // Log.d(TAG, "步数上传成功"); // } // } // @Override // public void onFailure(Call<Void> call, Throwable t) { // Log.e(TAG, "步数上传失败:" + t.getMessage()); // } // }); } }
2. 在Manifest中注册Receiver
别忘了在AndroidManifest.xml里注册这个Receiver,确保系统能找到它:
<receiver android:name=".StepUpdateReceiver" android:exported="false"> <intent-filter> <action android:name="com.google.android.gms.fitness.ACTION_DATA_AVAILABLE" /> </intent-filter> </receiver>
3. 注册PendingIntent到Google Fit
在你的GoogleApiClient连接成功后(比如onConnected回调里),创建PendingIntent并绑定到Recording API,这样有新步数数据时就会触发回调:
@Override public void onConnected(@Nullable Bundle bundle) { super.onConnected(bundle); Log.d(TAG, "GoogleApiClient 连接成功"); // 创建触发Receiver的Intent Intent intent = new Intent(this, StepUpdateReceiver.class); intent.setAction(Fitness.ACTION_DATA_AVAILABLE); // 根据Android版本选择合适的Flag,Android12+建议用FLAG_IMMUTABLE PendingIntent pendingIntent = PendingIntent.getBroadcast( this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); // 订阅步数数据更新 Fitness.RecordingApi.subscribe(mGoogleApiClient, DataType.TYPE_STEP_COUNT_DELTA) .setResultCallback(status -> { if (status.isSuccess()) { if (status.getStatusCode() == FitnessStatusCodes.SUCCESS_ALREADY_SUBSCRIBED) { Log.d(TAG, "已经订阅过步数更新"); } else { Log.d(TAG, "成功订阅步数更新"); } // 注册PendingIntent,让Google Fit在有新数据时触发 Fitness.RecordingApi.registerDataUpdateCallback(mGoogleApiClient, pendingIntent) .setResultCallback(callbackStatus -> { if (callbackStatus.isSuccess()) { Log.d(TAG, "PendingIntent 注册成功"); } else { Log.e(TAG, "PendingIntent 注册失败:" + callbackStatus.getMessage()); } }); } else { Log.e(TAG, "订阅步数更新失败:" + status.getMessage()); } }); }
一些关键注意事项
- 权限处理:Android10及以上需要申请
ACTIVITY_RECOGNITION权限,Android12+还要注意PendingIntent的Flag选择,避免兼容性问题。 - ApiClient生命周期:在Receiver里初始化ApiClient后,记得在数据处理完成后断开连接,防止内存泄漏。
- 耗时操作:如果上传服务器的逻辑比较耗时,建议在Receiver里启动WorkManager或者IntentService来处理,避免出现ANR。
内容的提问来源于stack exchange,提问作者Swapnil
相关产品推荐
相关产品推荐

