Menggunakan Sensor Manager untuk mengisi data langkah di aplikasi seluler, seperti yang dijelaskan dalam kami. Untuk informasi selengkapnya tentang cara mendesain dan mengelola UI aplikasi olahraga, rujuk ke Membuat aplikasi kebugaran dasar.
Memulai
Untuk mulai mengukur langkah penghitung langkah dasar dari
perangkat seluler, Anda harus menambahkan dependensi ke modul aplikasi
File build.gradle
. Pastikan Anda menggunakan dependensi versi terbaru.
Selain itu, saat Anda memperluas dukungan aplikasi ke faktor bentuk lainnya, seperti Wear OS,
tambahkan dependensi yang
diperlukan oleh faktor bentuk ini.
Berikut adalah beberapa contoh beberapa dependensi UI. Untuk daftar lengkap, lihat panduan Elemen UI ini.
implementation(platform("androidx.compose:compose-bom:2023.10.01"))
implementation("androidx.activity:activity-compose")
implementation("androidx.compose.foundation:foundation")
implementation("androidx.compose.material:material")
Mendapatkan sensor penghitung langkah
Setelah pengguna memberikan izin pengenalan aktivitas yang diperlukan, Anda dapat mengakses sensor penghitung langkah:
- Dapatkan objek
SensorManager
darigetSystemService()
. - Dapatkan sensor penghitung langkah dari
SensorManager
:
private val sensorManager by lazy {
getSystemService(Context.SENSOR_SERVICE) as SensorManager }
private val sensor: Sensor? by lazy {
sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER) }
Beberapa perangkat tidak memiliki sensor penghitung langkah. Anda harus memeriksa sensor dan menampilkan pesan error jika perangkat tidak memilikinya:
if (sensor == null) {
Text(text = "Step counter sensor is not present on this device")
}
Membuat layanan latar depan
Di aplikasi kebugaran dasar, Anda mungkin memiliki tombol untuk menerima peristiwa awal dan penghentian dari pengguna untuk langkah-langkah pelacakan.
Perhatikan praktik terbaik sensor. Secara khusus, sensor penghitung langkah hanya boleh menghitung langkah saat sensor telah terdaftar. Dengan mengaitkan pendaftaran sensor dengan latar depan sensor, sensor didaftarkan selama dibutuhkan, dan sensor dapat tetap terdaftar saat aplikasi tidak berada di latar depan.
Gunakan cuplikan berikut untuk membatalkan pendaftaran sensor di metode onPause()
layanan latar depan Anda:
override fun onPause() {
super.onPause()
sensorManager.unregisterListener(this)
}
Menganalisis data peristiwa
Untuk mengakses data sensor, implementasikan antarmuka SensorEventListener
. Catatan
Anda harus mengaitkan pendaftaran sensor dengan
siklus proses, membatalkan pendaftaran sensor saat layanan dijeda atau diakhiri. Tujuan
cuplikan berikut menunjukkan cara menerapkan antarmuka SensorEventListener
untuk Sensor.TYPE_STEP_COUNTER
:
private const val TAG = "STEP_COUNT_LISTENER"
context(Context)
class StepCounter {
private val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
private val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
suspend fun steps() = suspendCancellableCoroutine { continuation ->
Log.d(TAG, "Registering sensor listener... ")
val listener: SensorEventListener by lazy {
object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent?) {
if (event == null) return
val stepsSinceLastReboot = event.values[0].toLong()
Log.d(TAG, "Steps since last reboot: $stepsSinceLastReboot")
if (continuation.isActive) {
continuation.resume(stepsSinceLastReboot)
}
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
Log.d(TAG, "Accuracy changed to: $accuracy")
}
}
}
val supportedAndEnabled = sensorManager.registerListener(listener,
sensor, SensorManager.SENSOR_DELAY_UI)
Log.d(TAG, "Sensor listener registered: $supportedAndEnabled")
}
}
Membuat database untuk peristiwa sensor
Aplikasi Anda mungkin menampilkan layar tempat pengguna dapat melihat langkah mereka dari waktu ke waktu. Untuk menyediakan kemampuan ini di aplikasi Anda, gunakan library persistensi Room.
Cuplikan berikut membuat tabel yang berisi serangkaian jumlah langkah pengukuran, beserta waktu saat aplikasi Anda mengakses setiap pengukuran:
@Entity(tableName = "steps")
data class StepCount(
@ColumnInfo(name = "steps") val steps: Long,
@ColumnInfo(name = "created_at") val createdAt: String,
)
Membuat objek akses data (DAO) untuk membaca dan menulis data:
@Dao
interface StepsDao {
@Query("SELECT * FROM steps")
suspend fun getAll(): List<StepCount>
@Query("SELECT * FROM steps WHERE created_at >= date(:startDateTime) " +
"AND created_at < date(:startDateTime, '+1 day')")
suspend fun loadAllStepsFromToday(startDateTime: String): Array<StepCount>
@Insert
suspend fun insertAll(vararg steps: StepCount)
@Delete
suspend fun delete(steps: StepCount)
}
Untuk membuat instance DAO, buat objek RoomDatabase
:
@Database(entities = [StepCount::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun stepsDao(): StepsDao
}
Menyimpan data sensor ke dalam database
ViewModel menggunakan class StepCounter baru, sehingga Anda dapat menyimpan langkah-langkah segera saat Anda membacanya:
viewModelScope.launch {
val stepsFromLastBoot = stepCounter.steps()
repository.storeSteps(stepsFromLastBoot)
}
Class repository
akan terlihat seperti ini:
class Repository(
private val stepsDao: StepsDao,
) {
suspend fun storeSteps(stepsSinceLastReboot: Long) = withContext(Dispatchers.IO) {
val stepCount = StepCount(
steps = stepsSinceLastReboot,
createdAt = Instant.now().toString()
)
Log.d(TAG, "Storing steps: $stepCount")
stepsDao.insertAll(stepCount)
}
suspend fun loadTodaySteps(): Long = withContext(Dispatchers.IO) {
printTheWholeStepsTable() // DEBUG
val todayAtMidnight = (LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT).toString())
val todayDataPoints = stepsDao.loadAllStepsFromToday(startDateTime = todayAtMidnight)
when {
todayDataPoints.isEmpty() -> 0
else -> {
val firstDataPointOfTheDay = todayDataPoints.first()
val latestDataPointSoFar = todayDataPoints.last()
val todaySteps = latestDataPointSoFar.steps - firstDataPointOfTheDay.steps
Log.d(TAG, "Today Steps: $todaySteps")
todaySteps
}
}
}
}
Mengambil data sensor secara berkala
Jika menggunakan layanan latar depan, Anda tidak perlu mengonfigurasi WorkManager
karena, selama aplikasi Anda aktif melacak langkah pengguna,
jumlah langkah total yang diperbarui akan muncul di aplikasi Anda.
Namun, jika ingin mengelompokkan catatan langkah, Anda dapat menggunakan WorkManager
untuk
ukur langkah pada interval tertentu, misalnya setiap 15 menit sekali.
WorkManager
adalah komponen yang menjalankan latar belakang
untuk eksekusi yang terjamin. Pelajari lebih lanjut di codelab WorkManager.
Untuk mengonfigurasi objek Worker
guna mengambil data, ganti doWork()
, seperti yang ditampilkan dalam cuplikan kode berikut:
private const val TAG = " StepCounterWorker"
@HiltWorker
class StepCounterWorker @AssistedInject constructor(
@Assisted appContext: Context,
@Assisted workerParams: WorkerParameters,
val repository: Repository,
val stepCounter: StepCounter
) : CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
Log.d(TAG, "Starting worker...")
val stepsSinceLastReboot = stepCounter.steps().first()
if (stepsSinceLastReboot == 0L) return Result.success()
Log.d(TAG, "Received steps from step sensor: $stepsSinceLastReboot")
repository.storeSteps(stepsSinceLastReboot)
Log.d(TAG, "Stopping worker...")
return Result.success()
}
}
Untuk menyiapkan WorkManager
guna menyimpan jumlah langkah saat ini setiap 15 menit, lakukan
hal berikut:
- Perluas class
Application
untuk mengimplementasikanConfiguration.Provider
dalam antarmuka berbasis web yang sederhana. - Dalam metode
onCreate()
, antrekanPeriodicWorkRequestBuilder
.
Proses ini muncul dalam cuplikan kode berikut:
@HiltAndroidApp
@RequiresApi(Build.VERSION_CODES.S)
internal class PulseApplication : Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: HiltWorkerFactory
override fun onCreate() {
super.onCreate()
val myWork = PeriodicWorkRequestBuilder<StepCounterWorker>(
15, TimeUnit.MINUTES).build()
WorkManager.getInstance(this)
.enqueueUniquePeriodicWork("MyUniqueWorkName",
ExistingPeriodicWorkPolicy.UPDATE, myWork)
}
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.setMinimumLoggingLevel(android.util.Log.DEBUG)
.build()
}
Untuk menginisialisasi penyedia konten yang mengontrol akses ke langkah aplikasi Anda counter database segera setelah aplikasi dimulai, tambahkan elemen berikut ke file manifes aplikasi Anda:
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />