如何实时获取心率,而无需等待手镯自行完成(每10分钟一次)。我使用Google Fit API。 SmartBand2应用程序按需获取心率,但我怀疑它是否使用Google Fit API。 我用来设置监听器的代码是:
if (savedInstanceState != null) {
authInProgress = savedInstanceState.getBoolean(AUTH_PENDING);
}
mApiClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.SENSORS_API)
.addApi(Fitness.BLE_API)
.addApi(Fitness.HISTORY_API)
.addApi(Fitness.RECORDING_API)
.addScope(new Scope(Scopes.FITNESS_BODY_READ))
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ))
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.enableAutoManage(this, 0, this)//Al añadir la propiedad enableAutoManage, Google Play Services gestiona correctamente la conexión y desconexión.
.build();
initCallbacks();
@Override
public void onConnected(@Nullable final Bundle bundle) {
checkSelfPermissionBody();
}
private void registerFitnessDataListener(DataSource dataSource, DataType dataType) {
SensorRequest request = new SensorRequest.Builder()
.setDataSource( dataSource )
.setDataType( dataType )
.setSamplingRate( 3, TimeUnit.SECONDS )
.build();
Fitness.SensorsApi.add( mApiClient, request, this )
.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.d(TAG, "GoogleFit SensorApi successfully added" );
}
}
});
dataSource.getDevice();
}
@Override
public void onConnectionSuspended(final int i) {
}
@Override
public void onConnectionFailed(@NonNull final ConnectionResult connectionResult) {
if( !authInProgress ) {
try {
authInProgress = true;
connectionResult.startResolutionForResult( MainActivity.this, REQUEST_OAUTH );
} catch(IntentSender.SendIntentException e ) {
}
} else {
Log.d( TAG,"GoogleFit authInProgress" );
}
}
@Override
public void onDataPoint(final DataPoint dataPoint) {
for( final Field field : dataPoint.getDataType().getFields() ) {
final Value value = dataPoint.getValue( field );
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "Field: " + field.getName() + " Value: " + value, Toast.LENGTH_SHORT).show();
Log.d(TAG,"Field: " + field.getName() + " Value: " + value);
}
});
}
}
@Override
protected void onStart() {
super.onStart();
mApiClient.connect();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG,"ON ACTIVITY RESULT");
if( requestCode == REQUEST_OAUTH ) {
authInProgress = false;
if( resultCode == RESULT_OK ) {
if( !mApiClient.isConnecting() && !mApiClient.isConnected() ) {
mApiClient.connect();
Log.d(TAG,"GoogleFit RESULT_CONECTADO" );
}
} else if( resultCode == RESULT_CANCELED ) {
Log.d(TAG,"GoogleFit RESULT_CANCELED" );
}
} else {
Log.d(TAG,"GoogleFitr equestCode NOT request_oauth");
}
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG,"ON STOP");
Fitness.SensorsApi.remove( mApiClient, this )
.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
mApiClient.disconnect();
}
}
});
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(AUTH_PENDING, authInProgress);
}
private void bleScanDevice()
{
// 1. Define a callback object
BleScanCallback callback = new BleScanCallback() {
@Override
public void onDeviceFound(final BleDevice device) {
// A device that provides the requested data types is available
// -> Claim this BLE device (See next example)
Log.d(TAG,device.toString());
Log.d(TAG,"PRUEBA");
claimDevice(device);
}
@Override
public void onScanStopped() {
// The scan timed out or was interrupted
}
};
// 2. Create a scan request object:
// - Specify the data types you're interested in
// - Provide the callback object
StartBleScanRequest request = new StartBleScanRequest.Builder()
.setDataTypes(DataType.TYPE_HEART_RATE_BPM)
.setBleScanCallback(callback)
.build();
// 3. Invoke the Bluetooth Low Energy API with:
// - The Google API client
// - The scan request
PendingResult<Status> pendingResult =
Fitness.BleApi.startBleScan(mApiClient, request);
// 4. Check the result (see other examples)
}
private void claimDevice(BleDevice bleDevice)
{
// After the platform invokes your callback
// with a compatible BLE device (bleDevice):
// 1. Invoke the Bluetooth Low Energy API with:
// - The Google API client
// - The BleDevice object provided in the callback
PendingResult<Status> pendingResult =
Fitness.BleApi.claimBleDevice(mApiClient, bleDevice);
// 2. Check the result (see other examples)
}
private void releaseDevice(BleDevice bleDevice)
{
// When you no longer need the BLE device
// 1. Invoke the Bluetooth Low Energy API with:
// - The Google API client
// - The BLE device (from the initial scan)
PendingResult<Status> pendingResult =
Fitness.BleApi.unclaimBleDevice(mApiClient, bleDevice);
// 2. Check the result (see other examples)
}
我还尝试通过Record Fitness Data访问我的心率并使用健身史回收数据,但我只能获得最小,最大和平均回报。 代码:
private void readDataFitnessHistory()
{
// Setting a start and end date using a range of 1 week before this moment.
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
cal.add(Calendar.WEEK_OF_YEAR, -1);
long startTime = cal.getTimeInMillis();
java.text.DateFormat dateFormat = getDateInstance();
Log.i(TAG, "Range Start: " + dateFormat.format(startTime));
Log.i(TAG, "Range End: " + dateFormat.format(endTime));
DataReadRequest readRequest = new DataReadRequest.Builder()
// The data request can specify multiple data types to return, effectively
// combining multiple data queries into one call.
// In this example, it's very unlikely that the request is for several hundred
// datapoints each consisting of a few steps and a timestamp. The more likely
// scenario is wanting to see how many steps were walked per day, for 7 days.
.aggregate(DataType.TYPE_HEART_RATE_BPM, DataType.AGGREGATE_HEART_RATE_SUMMARY)
// Analogous to a "Group By" in SQL, defines how data should be aggregated.
// bucketByTime allows for a time span, whereas bucketBySession would allow
// bucketing by "sessions", which would need to be defined in code.
.bucketByTime(1, TimeUnit.DAYS)
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.build();
// Invoke the History API to fetch the data with the query and await the result of
// the read request.
DataReadResult dataReadResult =
Fitness.HistoryApi.readData(mApiClient, readRequest).await(1, TimeUnit.MINUTES);
DataSet dataSet = dataReadResult.getDataSet(DataType.TYPE_HEART_RATE_BPM);
dumpDataSet(dataSet);
displayBpmDataForToday();
}
private void showDataSet(DataSet dataSet) {
Log.d(TAG +" History", "Data returned for Data type: " + dataSet.getDataType().getName());
DateFormat dateFormat = DateFormat.getDateInstance();
DateFormat timeFormat = DateFormat.getTimeInstance();
List<DataPoint> dataPoints =dataSet.getDataPoints();
for (DataPoint dp : dataPoints) {
Log.d(TAG +" History", "Data point:");
Log.d(TAG +" History", "\tType: " + dp.getDataType().getName());
Log.d(TAG +" History", "\tStart: " + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
Log.d(TAG +" History", "\tEnd: " + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
for(Field field : dp.getDataType().getFields()) {
Log.d(TAG + " History", "\tField: " + field.getName() +
" Value: " + dp.getValue(field));
}
}
}
private void displayBpmDataForToday() {
DailyTotalResult result = Fitness.HistoryApi.readDailyTotal( mApiClient, DataType.TYPE_HEART_RATE_BPM ).await(1, TimeUnit.MINUTES);
showDataSet(result.getTotal());
}
private void suscribeDataFitness(){
Fitness.RecordingApi.subscribe(mApiClient, DataType.TYPE_HEART_RATE_BPM)
.setResultCallback(mSubscribeResultCallback);
}
private void listActiveFitnessSubscription()
{
Fitness.RecordingApi.listSubscriptions(mApiClient, DataType.TYPE_HEART_RATE_BPM)
// Create the callback to retrieve the list of subscriptions asynchronously.
.setResultCallback(mListSubscriptionsResultCallback);
}
private void unsuscribeDataFitness(){
Fitness.RecordingApi.unsubscribe(mApiClient, DataType.TYPE_HEART_RATE_BPM)
.setResultCallback(mCancelSubscriptionResultCallback);
}
private void initCallbacks() {
mSubscribeResultCallback = new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
if (status.getStatusCode()
== FitnessStatusCodes.SUCCESS_ALREADY_SUBSCRIBED) {
Log.i(TAG, "Existing subscription for activity detected.");
} else {
Log.i(TAG, "Successfully subscribed!");
}
} else {
Log.i(TAG, "There was a problem subscribing.");
}
}
};
mCancelSubscriptionResultCallback = new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Successfully unsubscribed for data type: TYPE_HEART_RATE_BPM");
} else {
// Subscription not removed
Log.i(TAG, "Failed to unsubscribe for data type: TYPE_HEART_RATE_BPM");
}
}
};
mListSubscriptionsResultCallback = new ResultCallback<ListSubscriptionsResult>() {
@Override
public void onResult(@NonNull ListSubscriptionsResult listSubscriptionsResult) {
for (Subscription subscription : listSubscriptionsResult.getSubscriptions()) {
DataType dataType = subscription.getDataType();
Log.e(TAG + "RecordingAPI", dataType.getName() );
for (Field field : dataType.getFields() ) {
Log.e( TAG + " RecordingAPI", field.toString() );
}
}
}
};
}
答案:
History: Type: com.google.heart_rate.summary
History: Start: 22 sept. 2017 10:40:06
D/DBGPRUEBA History: End: 22 sept. 2017 10:40:06
D/DBGPRUEBA History: Field: average Value: 71.13179
D/DBGPRUEBA History: Field: max Value: 86.0
D/DBGPRUEBA History: Field: min Value: 55.0
答案 0 :(得分:1)
要从心率传感器获取实时数据,您应该使用documentation中提到的Sensors API,并订阅一个侦听器,该侦听器将为您实时提供数据点。您还可以在SensorRequest.Builder()
中设置采样率,您可以每秒获取一次,而不是每10分钟获取一次。