在本教程中,您将学习如何与 Android 睡眠 API 交互,并对系统发送的事件流做出反应。Android 睡眠 API 会收集周围的亮度和设备移动等信息,以对用户何时处于睡眠或清醒状态做出假设。
此API可用于跟踪用户的睡眠模式,以帮助他们改善睡眠习惯。
在构建简单的睡眠跟踪应用程序时,您将如何:
为应用请求“活动识别”权限。
注册睡眠接收器以过滤和分析设备检测到的不同事件。
使用安卓睡眠接口
要使用此 API,您需要两段代码:
1、The client that lets you subscribe to sleep updates.
2、A , to receive the updates from the client.
此外,你需要在“设置”屏幕中请求用户收听其睡眠数据的权限,这些数据是他们在应用外部授予的。
此 API 将提供两组信息:
用户处于休眠状态的置信度,API 会在上次发布后几分钟定期报告。
API 在设备检测到用户处于唤醒状态后发出的每日睡眠段。
若要使用此 API,首先需要包含依赖项。打开应用 ‣ build.gradle 并在块中添加以下行:
implementation 'com.google.android.gms:play-services-location:18.0.0'
监听睡眠数据
在您可以执行任何其他操作之前,您需要接收睡眠数据。提供此信息的组件是 :BroadcastReceiver
打开睡眠接收器.kt.在此方法中,您将添加筛选数据的逻辑。
打开安卓智能.xml。你会看到已经在里面声明了:
<receiver
android:name=".receiver.SleepReceiver"
android:enabled="true"
android:exported="true" />
您需要在 Android 动漫中声明.xml以便系统知道您的应用程序中是否可用。
过滤睡眠数据
打开睡眠接收器。在onReceive()内添加以下语句:
if (SleepSegmentEvent.hasEvents(intent)) {
} else if (SleepClassifyEvent.hasEvents(intent)) {
}
接下来,将以下配套对象添加到类的底部:
companion object {
private const val TAG = "SLEEP_RECEIVER"
}
您将使用此标记将事件记录到控制台,并筛选将在几行中显示的文本。
现在,要把重点放在第一个分支的语句上!在行的正下方,添加:
val events =
SleepSegmentEvent.extractEvents(intent)
Log.d(TAG, "Logging SleepSegmentEvents")
for (event in events) {
Log.d(TAG,
"${event.startTimeMillis} to ${event.endTimeMillis} with status ${event.status}")
}
现在,您可以获取睡眠段,但您还希望对事件进行分类。您可以通过添加以下内容在语句的分支中执行此操作:
val events = SleepClassifyEvent.extractEvents(intent)
Log.d(TAG, "Logging SleepClassifyEvents")
for (event in events) {
Log.d(TAG,
"Confidence: ${event.confidence} - Light: ${event.light} - Motion: ${event.motion}"
)
}
同样,您需要提取有关事件的信息并将其数据打印到控制台,突出显示分类的置信度,光量和运动的值。
此时,如果生成并运行应用,则不会在控制台中看到任何输出。您仍然需要再执行几个步骤才能获得数据!
请求活动识别权限
要获取睡眠数据,您需要获得用户的许可才能访问它。这并不像其他权限那样简单,因为您需要打开数据的设置,并且用户需要向您的应用程序授予活动识别权限。但事情也没那么复杂。
首先,打开安卓智能.xml并在中添加以下权限:manifest
接下来,您需要在 MainActivity.kt 中创建一个方法,该方法将打开设置屏幕。打开“主要活动”并添加以下内容,导入:private fun requestActivityRecognitionPermission() {
val intent = Intent().apply {
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
data = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
startActivity(intent)
}
在这里,您将创建“设置”,并额外添加“活动识别”操作和应用包,然后运行 。
现在,由于您需要请求权限,因此您可以利用 API,这将有助于减少侦听活动结果的样板。
首先将活动 ktx 库添加到应用 ‣ build.gradle:
implementation 'androidx.activity:activity-ktx:1.2.3'
同步您的评分文件。这会将 和 添加到您的项目中。
然后,将此属性添加到:
private val permissionRequester: ActivityResultLauncher<String> =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (!isGranted) {
requestActivityRecognitionPermission()
} else {
// Request goes here
}
}
在这里,您将创建一个对象,该对象将侦听来自您的权限请求的 Activity 结果,并在此对象分析它后将其传递给您。
现在还不是构建和运行应用的时候。如果您尝试,它仍然不会显示任何数据。但它很快就会!
订阅睡眠数据更新
接下来,您将订阅睡眠数据更新。为此,您需要创建一个新类。在与“主要活动”相同的包中创建。类声明应如下所示:
class SleepRequestsManager(private val context: Context) {
}
此类将管理订阅和取消订阅更新。起初,您只需要负责订阅。为此,您需要将上下文作为构造函数参数传入。
接下来,您将添加一个方法,该方法将允许您订阅睡眠数据的更新。将此方法添加到新类中:
fun subscribeToSleepUpdates() {
}
现在,你有一个添加订阅的位置。
打开睡眠接收程序,向下滚动到伴随对象内的常量声明。在配套对象中,粘贴以下代码,该代码将从 中创建 作为参数传递的 :
fun createPendingIntent(context: Context): PendingIntent {
val intent = Intent(context, SleepReceiver::class.java)
return PendingIntent.getBroadcast(
context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
}
此时,你已拥有创建订阅逻辑所需的一切。回到睡眠请求管理器,并在类构造函数和空的 之间创建挂起的意图:
private val sleepReceiverPendingIntent by lazy {
SleepReceiver.createPendingIntent(context)
}
此“挂起意向”是您将在下一步中用于订阅更新的内容。
现在,您拥有订阅更新所需的一切,并且可以要求API将数据向下发送到您的接收器。在内部添加:
ActivityRecognition.getClient(context)
.requestSleepSegmentUpdates (sleepReceiverPendingIntent,
SleepSegmentRequest.getDefaultSleepSegmentRequest())
在此代码中,您将调用客户端并使用默认请求请求有关睡眠段的更新。
但是,在订阅之前,您仍然需要检查权限是否已到位。毕竟,您的用户始终可以将其删除。
如果仍然可以,您需要检查是否可以访问数据并订阅更新。如果不能,则需要请求权限。
首先,在上面添加此代码:
fun requestSleepUpdates(requestPermission: () -> Unit = {}) {
if (ContextCompat.checkSelfPermission(
context, Manifest.permission.ACTIVITY_RECOGNITION) ==
PackageManager.PERMISSION_GRANTED) {
subscribeToSleepUpdates()
} else {
requestPermission()
}
}
现在,返回“主要活动”。为您刚刚创建的 添加一个声明:
private val sleepRequestManager by lazy{
SleepRequestsManager(this)
}
现在,您可以请求睡眠更新。
滚动到您在 中看到的行,并将其替换为对订阅的调用:
sleepRequestManager.subscribeToSleepUpdates()
您直接调用更新,因为用户授予了您的应用程序权限,并且您最终进入了分支。因此,在此特定情况下,您可以安全地运行更新。
最后,你需要在用户打开应用时运行。向下滚动到底部显示的行,然后添加:
sleepRequestManager.requestSleepUpdates(requestPermission = {
permissionRequester.launch(ACTIVITY_RECOGNITION)
})
在这里,您请求请求更新,并指定如果它没有获取数据的权限,它应该如何表现。
现在,构建并运行。您会注意到一些事件开始出现在 Logcat 选项卡中!请确保您首先接受权限。
取消订阅更新
现在,你的应用不会停止侦听睡眠更新事件。但是,您可能需要取消订阅才能让用户在需要时启动和停止应用。
要创建取消订阅更新的逻辑,请打开睡眠请求管理器,然后在下面添加:
fun unsubscribeFromSleepUpdates() {
ActivityRecognition.getClient(context)
.removeSleepSegmentUpdates(sleepReceiverPendingIntent)
}
在这里,从客户端中删除订阅。
现在,返回“主要活动”。重写并调用取消子方法:
override fun onDestroy() {
super.onDestroy()
sleepRequestManager.unsubscribeFromSleepUpdates()
}
此代码可确保应用在用户退出时停止侦听和打印日志。
现在,构建并运行。请注意,一旦您退出,它就会停止打印日志!
处理重新启动
当设备重新启动时,Android 系统将终止您的应用,除非您的用户重新打开它,否则您的软件将无法运行。这是一个重要的考虑因素,因为您需要在用户不醒时记录用户睡眠模式,这通常是在晚上。
不幸的是,晚上也是大多数设备更新的时候,通常随后会重新启动。如果你的应用无法在重启完成时自动运行,则这些重启可能会导致数天没有数据。
你可以在启动过程中通过两个步骤使应用运行:
第一种是直接启动模式,发生在系统重新启动之后,但在用户登录到其设备之前。
另一种发生在启动完成并且用户解锁其设备之后。
在本教程中,您将学习如何对重新启动后登录其设备的用户做出反应。
侦听重新启动事件
如果希望应用在设备重启后侦听事件,则必须添加另一个 .打开 ,您注意到它是空的,可以填充。
此接收器将在设备重新启动并注册睡眠数据更新时运行。在下面添加一个这样的:
companion object {
private const val TAG = "SLEEP_BOOT_RECEIVER"
}
首先,声明另一个将用于错误日志的 String 常量。它与前一个不同,在Logcat中过滤输出时区分它。
现在,将其替换为:
override fun onReceive(context: Context, intent: Intent) {
val sleepRequestManager = SleepRequestsManager(context)
sleepRequestManager.requestSleepUpdates(requestPermission = {
Log.d(TAG, "Permission to listen for Sleep Activity has been removed")
})
}
这一次,如果用户删除了应用,则无法请求用户的权限,因为你的应用可能在用户登录之前正在运行。在这种情况下,他们将无法在解锁设备之前更改任何设置。您无法采取太多措施来防止这种情况,但您可以记录错误并在之后执行保留策略。
要在启动时安全运行,您需要在 AndroidManifest 中注册接收器.xml并添加一些特殊标志,这些标志会让系统知道您的应用程序可以在设备启动后立即运行。这已经在安卓动漫中.xml为您准备:
<receiver
android:name=".receiver.BootReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
请注意,您需要将权限添加到 Receiver 声明中。否则,Android 系统不会在启动完成时通知您的应用,也不会自动运行。
现在,您可以成功跟踪睡眠数据。