构建基本的健身应用
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
本指南将介绍如何构建基本的移动计步器应用,
是许多健康和健身应用。
此工作流集成了以下 API:
如需有关数据读取和所需工具的其他支持,请参阅使用
使用 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 管理界面状态
如需正确管理界面状态,请使用 ViewModel。
Jetpack Compose 和 ViewModel 可帮助您更深入地了解
工作流。
此外,使用界面分层,这是使用 Compose 构建界面的关键部分
并且能让您遵循架构最佳实践
单向数据流。如需详细了解界面分层,请参阅
界面层文档。
在此示例应用中,界面有三种基本状态:
- 正在加载:显示一个旋转的圆圈。
- 内容:显示您今天的步数信息。
- 错误:在出现问题时显示消息。
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 界面收集此 Flow
作为 Compose State
,并对其执行操作:
val state: TodayScreenState = todayScreenViewModel.currentScreenState.collectAsState().value
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-27。
[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["没有我需要的信息","missingTheInformationINeed","thumb-down"],["太复杂/步骤太多","tooComplicatedTooManySteps","thumb-down"],["内容需要更新","outOfDate","thumb-down"],["翻译问题","translationIssue","thumb-down"],["示例/代码问题","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2025-07-27。"],[],[],null,["# Build a basic fitness app\n\n| **Note:** This guide uses `SensorManager` for retrieving steps data. We recommend using the [Recording API on mobile](/health-and-fitness/guides/recording-api) for recording steps in a power-efficient way.\n\nThis guide walks you through building a basic mobile step counter app, which\nis a common foundation for many Health \\& Fitness apps.\n\nThis workflow integrates the following APIs:\n\n- [SensorManager](/guide/topics/sensors/sensors_motion) for retrieving steps data from a mobile device.\n- [Room](/training/data-storage/room) for local data storage.\n- [Health Connect](/health-and-fitness/guides/health-connect) for storing and sharing health and fitness data on device.\n\nFor additional support on data reading and the tools necessary, refer to [Use\nAndroid Sensor Manager to track steps from a mobile device](/health-and-fitness/guides/basic-fitness-app/read-step-count-data).\n\nIf you haven't already set up your development environment for using\n[Health Connect](/health-and-fitness/guides/health-connect), follow these\n[getting started](/health-and-fitness/guides/health-connect/develop/get-started)\nsteps.\n\nRequest permissions on handheld device\n--------------------------------------\n\nBefore getting exercise data you must request and be granted the appropriate\npermissions.\n\nAs a best practice, only request the permissions you need, and make sure to\n[request each permission in context](/training/permissions/requesting#workflow_for_requesting_permissions), instead of requesting all\npermissions at once when the user starts the app.\n\nThe [step counter sensor](/guide/topics/sensors/sensors_motion#sensors-motion-stepcounter), which many exercise apps rely on, uses the\n`ACTIVITY_RECOGNITION` permission. Add this permission in your AndroidManifest.xml\nfile: \n\n \u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n \u003cmanifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tools=\"http://schemas.android.com/tools\"\u003e\n\n \u003cuses-permission android:name=\"android.permission.ACTIVITY_RECOGNITION\"/\u003e\n\n \u003c/manifest\u003e\n\nTo request the `ACTIVITY_RECOGNITION` permission at runtime refer to the\n[permission request documentation](/training/permissions/requesting#request-permission).\n\nYou will also need to declare a `FOREGROUND_SERVICE` in the manifest. Since you\nare requesting the `ACTIVITY_RECOGNITION` permission, declare\n`FOREGROUND_SERVICE_TYPE_HEALTH`: \n\n \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE\"/\u003e\n \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE_HEALTH\"/\u003e\n\nVisit [Foreground services](/develop/background-work/services/fgs)\nto learn more about foreground services and foreground service types.\n\nManage UI state using a ViewModel\n---------------------------------\n\nTo properly manage the UI state, use a ViewModel.\n[Jetpack Compose and ViewModels](/jetpack/compose/libraries#viewmodel) offers you a more in-depth look at this\nworkflow.\n\nAlso, use UI layering, which is a critical part for building UIs with Compose\nand lets you follow architecture best practices, such as\n[Unidirectional Data Flow](/jetpack/compose/architecture#udf). To learn more about UI layering, refer to the\n[UI layer documentation](/topic/architecture/ui-layer).\n\nIn this example app, the UI has three basic states:\n\n- **Loading:** Shows a spinning circle.\n- **Content:** Shows information about your steps for today.\n- **Error:** Shows a message when something goes wrong.\n\nThe `ViewModel` exposes these states as a Kotlin `Flow`. Use a sealed class to\ncontain the classes and objects that represent the possible states: \n\n class TodayScreenViewModel(...) {\n\n val currentScreenState: MutableStateFlow\u003cTodayScreenState\u003e = MutableStateFlow(Loading)\n\n [...]\n\n }\n\n sealed class TodayScreenState {\n data object Loading : TodayScreenState()\n data class Content(val steps: Long, val dailyGoal: Long) : TodayScreenState()\n data object Error: TodayScreenState()\n }\n\nCompose UI then collects this `Flow` as a Compose `State` and acts on it: \n\n val state: TodayScreenState = todayScreenViewModel.currentScreenState.collectAsState().value"]]