Meningkatkan pengalaman kesehatan dan kebugaran aplikasi dengan memperluasnya ke perangkat wearable perangkat yang didukung oleh Wear OS.
Menambahkan modul Wear OS
Android Studio menyediakan wizard praktis untuk menambahkan modul Wear OS ke aplikasi Anda. Di beberapa File > Menu Modul Baru, pilih Wear OS, seperti yang ditunjukkan di bawah gambar:
Penting untuk diperhatikan bahwa Minimum SDK harus berupa API 30 atau yang lebih tinggi agar Anda dapat menggunakan Fitur Kesehatan versi terbaru. Fitur Kesehatan memudahkan pelacakan metrik dan pencatatan data dengan mengonfigurasi sensor secara otomatis.
Setelah menyelesaikan wizard, sinkronkan project Anda. Perintah Run berikut akan muncul:
Tindakan ini memungkinkan Anda menjalankan modul Wear OS pada perangkat wearable. Anda memiliki dua opsi:
Jalankan di emulator.
Berjalan di perangkat sungguhan.
Menjalankan konfigurasi akan men-deploy aplikasi ke emulator Wear OS atau perangkat dan menampilkan "halo dunia" pengalaman yang lancar bagi developer. Ini adalah pengaturan UI dasar, menggunakan Compose untuk Wear OS, guna memulai aplikasi Anda.
Menambahkan Fitur Kesehatan dan Hilt
Integrasikan library berikut ke dalam modul Wear OS Anda:
- Fitur Kesehatan: membuat akses sensor dan data di smartwatch sangat nyaman dan hemat daya.
- Hilt: Memungkinkan pengelolaan dan injeksi dependensi yang efektif.
Membuat Pengelola Fitur Kesehatan
Untuk mempermudah penggunaan Fitur Kesehatan, dan menampilkan bagian yang lebih kecil dan lebih lancar, Anda dapat membuat wrapper seperti ini:
private const val TAG = "WATCHMAIN"
class HealthServicesManager(context: Context) {
private val measureClient = HealthServices.getClient(context).measureClient
suspend fun hasHeartRateCapability() = runCatching {
val capabilities = measureClient.getCapabilities()
(DataType.HEART_RATE_BPM in capabilities.supportedDataTypesMeasure)
}.getOrDefault(false)
/**
* Returns a cold flow. When activated, the flow will register a callback for heart rate data
* and start to emit messages. When the consuming coroutine is canceled, the measure callback
* is unregistered.
*
* [callbackFlow] creates a bridge between a callback-based API and Kotlin flows.
*/
@ExperimentalCoroutinesApi
fun heartRateMeasureFlow(): Flow<MeasureMessage> = callbackFlow {
val callback = object : MeasureCallback {
override fun onAvailabilityChanged(dataType: DeltaDataType<*, *>, availability: Availability) {
// Only send back DataTypeAvailability (not LocationAvailability)
if (availability is DataTypeAvailability) {
trySendBlocking(MeasureMessage.MeasureAvailability(availability))
}
}
override fun onDataReceived(data: DataPointContainer) {
val heartRateBpm = data.getData(DataType.HEART_RATE_BPM)
Log.d(TAG, "💓 Received heart rate: ${heartRateBpm.first().value}")
trySendBlocking(MeasureMessage.MeasureData(heartRateBpm))
}
}
Log.d(TAG, "⌛ Registering for data...")
measureClient.registerMeasureCallback(DataType.HEART_RATE_BPM, callback)
awaitClose {
Log.d(TAG, "👋 Unregistering for data")
runBlocking {
measureClient.unregisterMeasureCallback(DataType.HEART_RATE_BPM, callback)
}
}
}
}
sealed class MeasureMessage {
class MeasureAvailability(val availability: DataTypeAvailability) : MeasureMessage()
class MeasureData(val data: List<SampleDataPoint<Double>>) : MeasureMessage()
}
Setelah Anda membuat modul Hilt untuk mengelolanya, menggunakan cuplikan berikut:
@Module
@InstallIn(SingletonComponent::class)
internal object DataModule {
@Provides
@Singleton
fun provideHealthServices(@ApplicationContext context: Context): HealthServicesManager = HealthServicesManager(context)
}
Anda dapat memasukkan HealthServicesManager
seperti dependensi Hilt lainnya.
HealthServicesManager
baru menyediakan metode heartRateMeasureFlow()
yang
mendaftarkan pemroses untuk monitor jantung dan memancarkan data yang diterima.
Mengaktifkan update data pada perangkat wearable
Pembaruan data terkait kebugaran memerlukan izin BODY_SENSORS
. Jika Anda
belum melakukannya, deklarasikan izin BODY_SENSORS
di
file manifes aplikasi Anda. Kemudian, minta izin, seperti yang ditunjukkan dalam cuplikan ini:
val permissionState = rememberPermissionState(
permission = Manifest.permission.BODY_SENSORS,
onPermissionResult = { granted -> /* do something */ }
)
[...]
if (permissionState.status.isGranted) {
// do something
} else {
permissionState.launchPermissionRequest()
}
Jika Anda menguji aplikasi di perangkat fisik, data akan mulai diupdate.
Mulai Wear OS 4, emulator juga otomatis menampilkan data pengujian. Pada sebelumnya versi, Anda dapat melakukan simulasi aliran data dari sensor. Di terminal jalankan perintah ADB ini:
adb shell am broadcast \
-a "whs.USE_SYNTHETIC_PROVIDERS" \
com.google.android.wearable.healthservices
Untuk melihat nilai detak jantung yang berbeda, coba simulasikan berbagai latihan. Perintah ini menyimulasikan aktivitas berjalan:
adb shell am broadcast \
-a "whs.synthetic.user.START_WALKING" \
com.google.android.wearable.healthservices
Perintah ini menyimulasikan proses yang berjalan:
adb shell am broadcast \
-a "whs.synthetic.user.START_RUNNING" \
com.google.android.wearable.healthservices
Untuk berhenti menyimulasikan data, jalankan perintah ini:
adb shell am broadcast -a \
"whs.USE_SENSOR_PROVIDERS" \
com.google.android.wearable.healthservices
Membaca data detak jantung
Dengan izin BODY_SENSORS
diberikan, Anda dapat membaca detak jantung pengguna
(heartRateMeasureFlow()
) di HealthServicesManager
. Di aplikasi Wear OS
UI, nilai detak jantung saat ini yang muncul, diukur oleh sensor di
perangkat wearable.
Di ViewModel
, mulai kumpulkan data menggunakan objek aliran detak jantung,
seperti yang ditampilkan dalam cuplikan berikut:
val hr: MutableState<Double> = mutableStateOf(0.0)
[...]
healthServicesManager
.heartRateMeasureFlow()
.takeWhile { enabled.value }
.collect { measureMessage ->
when (measureMessage) {
is MeasureData -> {
val latestHeartRateValue = measureMessage.data.last().value
hr.value = latestHeartRateValue
}
is MeasureAvailability -> availability.value =
measureMessage.availability
}
}
Gunakan objek composable yang mirip dengan berikut ini untuk menampilkan data langsung di UI aplikasi Anda:
val heartRate by viewModel.hr
Text(
text = "Heart Rate: $heartRate",
style = MaterialTheme.typography.display1
)
Mengirim data ke perangkat genggam
Untuk mengirim data kesehatan dan kebugaran ke perangkat genggam, gunakan DataClient
di Fitur Kesehatan. Cuplikan kode berikut menunjukkan cara mengirim ikon hati
memberi rating pada data yang sebelumnya dikumpulkan oleh aplikasi Anda:
class HealthServicesManager(context: Context) {
private val dataClient by lazy { Wearable.getDataClient(context) }
[...]
suspend fun sendToHandheldDevice(heartRate: Int) {
try {
val result = dataClient
.putDataItem(PutDataMapRequest
.create("/heartrate")
.apply { dataMap.putInt("heartrate", heartRate) }
.asPutDataRequest()
.setUrgent())
.await()
Log.d(TAG, "DataItem saved: $result")
} catch (cancellationException: CancellationException) {
throw cancellationException
} catch (exception: Exception) {
Log.d(TAG, "Saving DataItem failed: $exception")
}
}
}
Menerima data di ponsel
Untuk menerima data di ponsel, buat
WearableListenerService
:
@AndroidEntryPoint
class DataLayerListenerService : WearableListenerService() {
@Inject
lateinit var heartRateMonitor: HeartRateMonitor
override fun onDataChanged(dataEvents: DataEventBuffer) {
dataEvents.forEach { event ->
when (event.type) {
DataEvent.TYPE_CHANGED -> {
event.dataItem.run {
if (uri.path?.compareTo("/heartrate") == 0) {
val heartRate = DataMapItem.fromDataItem(this)
.dataMap.getInt(HR_KEY)
Log.d("DataLayerListenerService",
"New heart rate value received: $heartRate")
heartRateMonitor.send(heartRate)
}
}
}
DataEvent.TYPE_DELETED -> {
// DataItem deleted
}
}
}
}
}
Setelah menyelesaikan langkah ini, perhatikan beberapa detail menarik:
- Anotasi
@AndroidEntryPoint
memungkinkan kita menggunakan Hilt di class ini @Inject lateinit var heartRateMonitor: HeartRateMonitor
memang akan menginjeksikan dependensi di class ini- Class ini menerapkan
onDataChanged()
dan menerima kumpulan peristiwa yang Anda dapat mengurai dan menggunakan
Logika HeartRateMonitor
berikut memungkinkan Anda mengirim detak jantung yang diterima
nilai tersebut ke bagian lain codebase aplikasi Anda:
class HeartRateMonitor {
private val datapoints = MutableSharedFlow<Int>(extraBufferCapacity = 10)
fun receive(): SharedFlow<Int> = datapoints.asSharedFlow()
fun send(hr: Int) {
datapoints.tryEmit(hr)
}
}
Bus data menerima peristiwa dari metode onDataChanged()
dan membuatnya
yang tersedia untuk observer data menggunakan SharedFlow
.
Bit terakhir adalah deklarasi Service
di aplikasi ponsel
AndroidManifest.xml
:
<service
android:name=".DataLayerListenerService"
android:exported="true">
<intent-filter>
<!-- listeners receive events that match the action and data filters -->
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data
android:host="*"
android:pathPrefix="/heartrate"
android:scheme="wear" />
</intent-filter>
</service>
Menampilkan data real-time pada perangkat genggam
Di bagian aplikasi yang berjalan pada perangkat genggam, injeksikan
HeartRateMonitor
ke dalam konstruktor model tampilan Anda. HeartRateMonitor
ini
mengamati data detak jantung dan memancarkan update UI sesuai kebutuhan.