기본 피트니스 앱 빌드

이 가이드에서는 많은 건강/피트니스 앱의 일반적인 기반인 기본 모바일 걸음수 측정기 앱을 빌드하는 방법을 안내합니다.

이 워크플로는 다음 API를 통합합니다.

  • SensorManager: 휴대기기에서 걸음 수 데이터를 검색합니다.
  • Room: 로컬 데이터 저장소
  • 헬스 커넥트: 기기에 건강 및 피트니스 데이터를 저장하고 공유합니다.

데이터 읽기 및 필요한 도구에 관한 추가 지원은 Android 센서 관리자를 사용하여 휴대기기에서 걸음 수 추적하기를 참고하세요.

헬스 커넥트를 사용하기 위한 개발 환경을 아직 설정하지 않았다면 이 시작하기 단계를 따르세요.

휴대기기에서 권한 요청

운동 데이터를 가져오려면 먼저 적절한 권한을 요청하고 부여받아야 합니다.

사용자가 앱을 시작할 때 한 번에 모든 권한을 요청하는 대신 필요한 권한만 요청하고 컨텍스트에 따라 각 권한을 요청하는 것이 좋습니다.

많은 운동 앱에서 사용하는 걸음수 측정기 센서ACTIVITY_RECOGNITION 권한을 사용합니다. AndroidManifest.xml 파일에 이 권한을 추가합니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools">

  <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>

</manifest>

런타임 시 ACTIVITY_RECOGNITION 권한을 요청하려면 권한 요청 문서를 참고하세요.

또한 매니페스트에서 FOREGROUND_SERVICE를 선언해야 합니다. ACTIVITY_RECOGNITION 권한을 요청하므로 FOREGROUND_SERVICE_TYPE_HEALTH를 선언합니다.

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH"/>

포그라운드 서비스 및 포그라운드 서비스 유형에 관한 자세한 내용은 포그라운드 서비스를 참고하세요.

ViewModel을 사용하여 UI 상태 관리

UI 상태를 올바르게 관리하려면 ViewModel을 사용합니다. Jetpack Compose 및 ViewModel에서 이 워크플로를 더 자세히 살펴볼 수 있습니다.

또한 Compose를 사용하여 UI를 빌드하는 데 중요한 부분이며 단방향 데이터 흐름과 같은 아키텍처 권장사항을 따를 수 있는 UI 레이어링을 사용합니다. UI 레이어링에 관한 자세한 내용은 UI 레이어 문서를 참고하세요.

이 예시 앱에서는 UI에 세 가지 기본 상태가 있습니다.

  • 로드 중: 회전하는 원이 표시됩니다.
  • 콘텐츠: 오늘의 걸음 수 정보를 표시합니다.
  • 오류: 문제가 발생하면 메시지를 표시합니다.

ViewModel는 이러한 상태를 Kotlin Flow로 노출합니다. 봉인 클래스를 사용하여 가능한 상태를 나타내는 클래스와 객체를 포함합니다.

class TodayScreenViewModel(...) {

  val currentScreenState: MutableStateFlow<TodayScreenState> = MutableStateFlow(Loading)

  [...]

}

sealed class TodayScreenState {
    data object Loading : TodayScreenState()
    data class Content(val steps: Long, val dailyGoal: Long) : TodayScreenState()
    data object Error: TodayScreenState()
}

그런 다음 Compose UI는 이 Flow를 Compose State로 수집하고 이에 따라 작동합니다.

val state: TodayScreenState = todayScreenViewModel.currentScreenState.collectAsState().value