Bu kılavuzda açıklandığı gibi, bir mobil uygulamadaki adım verilerini doldurmak için Sensör Yöneticisi'ni kullanın. Bir egzersiz uygulaması kullanıcı arayüzü tasarlama ve yönetme hakkında daha fazla bilgi için Temel bir fitness uygulaması oluşturma konusuna bakın.
Başlarken
Mobil cihazınızdan temel adım sayacınızın adımlarını ölçmeye başlamak için uygulama modülü build.gradle
dosyanıza bağımlılıkları eklemeniz gerekir. Bağımlılıkların en son sürümlerini kullandığınızdan emin olun.
Ayrıca, uygulamanızın desteğini Wear OS gibi diğer form faktörlerini içerecek şekilde genişletirken, bu form faktörlerinin gerektirdiği bağımlılıkları ekleyin.
Aşağıda, kullanıcı arayüzü bağımlılıklarından bazılarına birkaç örnek verilmiştir. Eksiksiz liste için bu Kullanıcı Arayüzü Öğeleri kılavuzuna bakın.
implementation(platform("androidx.compose:compose-bom:2023.10.01"))
implementation("androidx.activity:activity-compose")
implementation("androidx.compose.foundation:foundation")
implementation("androidx.compose.material:material")
Adım sayacı sensörünü al
Kullanıcı gerekli etkinlik tanıma iznini verdikten sonra, adım sayacı sensörüne erişebilirsiniz:
getSystemService()
öğesindenSensorManager
nesnesini edinin.SensorManager
öğesinden adım sayacı sensörünü alın:
private val sensorManager by lazy {
getSystemService(Context.SENSOR_SERVICE) as SensorManager }
private val sensor: Sensor? by lazy {
sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER) }
Bazı cihazlarda adım sayacı sensörü yoktur. Sensör olup olmadığını kontrol etmeniz ve cihazda yoksa bir hata mesajı göstermeniz gerekir:
if (sensor == null) {
Text(text = "Step counter sensor is not present on this device")
}
Ön plan hizmetinizi oluşturma
Temel bir fitness uygulamasında, adımları izlemek üzere kullanıcıdan başlatma ve durdurma etkinlikleri almayı sağlayan bir düğmeniz olabilir.
Sensör en iyi uygulamalarını göz önünde bulundurun. Özellikle, adım sayacı sensörü yalnızca sensör dinleyicisi kayıtlıyken adımları saymalıdır. Sensör kaydını bir ön plan hizmetiyle ilişkilendirerek sensör gerektiği sürece kayıtlı kalır ve uygulama ön planda değilken sensör kayıtlı kalabilir.
Ön plan hizmetinizin onPause()
yöntemindeki sensörün kaydını iptal etmek için aşağıdaki snippet'i kullanın:
override fun onPause() {
super.onPause()
sensorManager.unregisterListener(this)
}
Etkinlik verilerini analiz etme
Sensör verilerine erişmek için SensorEventListener
arayüzünü uygulayın. Sensör kaydını ön plan hizmetinizin kullanım ömrüyle ilişkilendirmeniz gerektiğini ve hizmet duraklatıldığında veya sona erdiğinde sensörün kaydını iptal etmeniz gerektiğini unutmayın. Aşağıdaki snippet, Sensor.TYPE_STEP_COUNTER
için SensorEventListener
arayüzünün nasıl uygulanacağını gösterir:
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")
}
}
Sensör olayları için bir veritabanı oluşturun
Uygulamanızda, kullanıcının zaman içinde adımlarını görebileceği bir ekran gösterilebilir. Uygulamanızda bu özelliği sağlamak için Oda kalıcılığı kitaplığı'nı kullanın.
Aşağıdaki snippet, bir dizi adım sayısı ölçümünü ve uygulamanızın her bir ölçüme eriştiği süreyi içeren bir tablo oluşturur:
@Entity(tableName = "steps")
data class StepCount(
@ColumnInfo(name = "steps") val steps: Long,
@ColumnInfo(name = "created_at") val createdAt: String,
)
Verileri okumak ve yazmak için bir veri erişimi nesnesi (DAO) oluşturun:
@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)
}
DAO'yu örneklendirmek için bir RoomDatabase
nesnesi oluşturun:
@Database(entities = [StepCount::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun stepsDao(): StepsDao
}
Sensör verilerini veritabanında depolayın
ViewModel, yeni StepCounter sınıfını kullanır. Böylece adımları okur okumaz saklayabilirsiniz:
viewModelScope.launch {
val stepsFromLastBoot = stepCounter.steps()
repository.storeSteps(stepsFromLastBoot)
}
repository
sınıfı şöyle görünür:
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
}
}
}
}
Sensör verilerini düzenli olarak alma
Ön plan hizmeti kullanıyorsanız WorkManager
uygulamasını yapılandırmanız gerekmez. Uygulamanızın kullanıcının adımlarını etkin bir şekilde izlediği süre boyunca, güncellenen toplam adım sayısı uygulamanızda görünmelidir.
Ancak adım kayıtlarınızı toplu hale getirmek istiyorsanız adımları belirli bir aralıkta (ör. 15 dakikada bir) ölçmek için WorkManager
kullanabilirsiniz.
WorkManager
, garantili yürütme için arka plan işlemini gerçekleştiren bileşendir. WorkManager codelab'inden daha fazla bilgi edinin.
Worker
nesnesini verileri alacak şekilde yapılandırmak için aşağıdaki kod snippet'inde gösterildiği gibi doWork()
yöntemini geçersiz kılın:
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()
}
}
WorkManager
işlevini, mevcut adım sayısını 15 dakikada bir kaydedecek şekilde ayarlamak için aşağıdakileri yapın:
Configuration.Provider
arayüzünü uygulamak içinApplication
sınıfını genişletin.onCreate()
yönteminde birPeriodicWorkRequestBuilder
öğesini sıraya alın.
Bu işlem aşağıdaki kod snippet'inde görünür:
@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()
}
Uygulama başladıktan hemen sonra uygulamanızın adım sayacı veritabanına erişimi kontrol eden içerik sağlayıcıyı başlatmak için aşağıdaki öğeyi uygulamanızın manifest dosyasına ekleyin:
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />