API ghi trên thiết bị di động

API Ghi lại trên thiết bị di động cho phép ứng dụng của bạn ghi lại số bước trên thiết bị di động theo cách tiết kiệm pin. API này không dùng tài khoản, nghĩa là không yêu cầu Tài khoản Google để sử dụng dịch vụ và dữ liệu được lưu trữ trên thiết bị.

Hướng dẫn này chỉ cho bạn cách sử dụng API Ghi âm trên thiết bị di động để đảm bảo sức khoẻ và trải nghiệm tập thể hình.

Chi tiết đáng chú ý

Có một số tính năng đáng chú ý của riêng API Bản ghi trên thiết bị di động:

  • Sau khi gói thuê bao ghi lại bắt đầu hoặc được gia hạn, dữ liệu kể từ lần gần nhất gói thuê bao - trong tối đa 10 ngày - có thể truy cập được.
  • Bạn chỉ có thể xem dữ liệu khi có một gói thuê bao đang hoạt động. Nếu một gói thuê bao bị xoá bằng cách gọi unsubscribe, bạn sẽ không thể truy cập vào dữ liệu bước đã thu thập.

Loại dữ liệu

API Bản ghi trên thiết bị di động có thể ghi lại các loại dữ liệu sau:

Bắt đầu

Để bắt đầu, hãy thêm phần phụ thuộc sau vào tệp build.gradle:

Kotlin DSL

plugin {
  id("com.android.application")
}

...

dependencies {
  implementation("com.google.android.gms:play-services-fitness:21.2.0")
}

DSL bắt mắt

apply plugin: 'com.android.application'

...

dependencies {
  implementation 'com.google.android.gms:play-services-fitness:21.2.0'
}

Yêu cầu cấp quyền

Để ghi lại dữ liệu bằng API Bản ghi trên thiết bị di động, ứng dụng của bạn sẽ cần yêu cầu quyền sau đây:

  • android.permission.ACTIVITY_RECOGNITION

Kiểm tra phiên bản Dịch vụ Play

Để sử dụng API Bản ghi trên thiết bị di động, người dùng phải có Dịch vụ Google Play đã cập nhật thành LOCAL_RECORDING_CLIENT_MIN_VERSION_CODE. Bạn có thể kiểm tra để tìm bằng phương thức isGooglePlayServicesAvailable:

val hasMinPlayServices = isGooglePlayServicesAvailable(context, LocalRecordingClient.LOCAL_RECORDING_CLIENT_MIN_VERSION_CODE)

if(hasMinPlayServices != ConnectionResult.SUCCESS) {
  // Prompt user to update their device's Google Play services app and return
}

// Continue with Recording API functions

Ngược lại, nếu phiên bản Dịch vụ Google Play của người dùng quá thấp, hệ thống gửi một ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED ngoại lệ.

Đăng ký dữ liệu về thể chất

Để yêu cầu thu thập dữ liệu số bước ở chế độ nền, hãy sử dụng subscribe, như minh hoạ trong đoạn mã sau:

val localRecordingClient = FitnessLocal.getLocalRecordingClient(this)
// Subscribe to steps data
localRecordingClient.subscribe(LocalDataType.TYPE_STEP_COUNT_DELTA)
  .addOnSuccessListener {
    Log.i(TAG, "Successfully subscribed!")
  }
  .addOnFailureListener { e ->
    Log.w(TAG, "There was a problem subscribing.", e)
  }

Đọc và xử lý dữ liệu thể dục

Sau khi đăng ký, hãy yêu cầu dữ liệu bằng phương thức readData. Sau đó, bạn có thể lấy LocalDataPoint từ LocalDataSet thu được bằng cách tạo một LocalDataReadRequest như trong mã sau snippet:

val endTime = LocalDateTime.now().atZone(ZoneId.systemDefault())
val startTime = endTime.minusWeeks(1)
val readRequest =
  LocalDataReadRequest.Builder()
    // The data request can specify multiple data types to return,
    // effectively combining multiple data queries into one call.
    // This example demonstrates aggregating only one data type.
    .aggregate(LocalDataType.TYPE_STEP_COUNT_DELTA)
    // Analogous to a "Group By" in SQL, defines how data should be
    // aggregated. bucketByTime allows bucketing by time span.
    .bucketByTime(1, TimeUnit.DAYS)
    .setTimeRange(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS)
    .build()

  localRecordingClient.readData(readRequest).addOnSuccessListener { response ->
    // The aggregate query puts datasets into buckets, so flatten into a
    // single list of datasets.
    for (dataSet in response.buckets.flatMap { it.dataSets }) {
      dumpDataSet(dataSet)
    }
  }
  .addOnFailureListener { e ->
    Log.w(TAG,"There was an error reading data", e)
  }

fun dumpDataSet(dataSet: LocalDataSet) {
  Log.i(TAG, "Data returned for Data type: ${dataSet.dataType.name}")
  for (dp in dataSet.dataPoints) {
    Log.i(TAG,"Data point:")
    Log.i(TAG,"\tType: ${dp.dataType.name}")
    Log.i(TAG,"\tStart: ${dp.getStartTime(TimeUnit.HOURS)}")
    Log.i(TAG,"\tEnd: ${dp.getEndTime(TimeUnit.HOURS)}")
    for (field in dp.dataType.fields) {
      Log.i(TAG,"\tLocalField: ${field.name.toString()} LocalValue: ${dp.getValue(field)}")
    }
  }
}

LocalRecordingClient liên tục cập nhật hoạt động thu thập dữ liệu của mình. Bạn có thể sử dụng readData để lấy các số mới nhất bất cứ lúc nào.

Xin lưu ý rằng LocalRecordingClient lưu trữ dữ liệu trong tối đa 10 ngày. Để giảm nguy cơ mất dữ liệu, bạn có thể sử dụng WorkManager để định kỳ thu thập dữ liệu trong nền.

Hủy đăng ký dữ liệu thể dục

Để giải phóng tài nguyên, bạn phải đảm bảo huỷ đăng ký khỏi thu thập dữ liệu cảm biến khi ứng dụng của bạn không cần dữ liệu đó nữa. Người nhận huỷ đăng ký, hãy sử dụng phương thức unsubscribe:

val localRecordingClient = FitnessLocal.getLocalRecordingClient(this)
// Unsubscribe from steps data
localRecordingClient.unsubscribe(LocalDataType.TYPE_STEP_COUNT_DELTA)
  .addOnSuccessListener {
    Log.i(TAG, "Successfully unsubscribed!")
  }
  .addOnFailureListener { e ->
    Log.w(TAG, "There was a problem unsubscribing.", e)
  }