当用户不再使用手表时,Wear OS 会自动使处于活跃状态的应用进入低功耗模式。这称为“系统氛围模式”。如果用户在一定时间范围内再次与手表进行互动,Wear OS 会使用户重新进入应用中上次离开时的位置。
对于特定用例,例如用户想在跑步期间查看心率和步速,您还可以控制在低功耗氛围模式下显示哪些内容。在氛围模式和互动模式下均处于运行状态的 Wear OS 应用称为始终开启的应用。
让应用始终可见会影响电池续航时间,因此在为应用添加这项功能时,应该考虑这个影响。
配置项目
如需支持氛围模式,请按以下步骤操作:
- 根据创建和运行穿戴式应用页面上的配置,创建或更新您的项目。
- 向 Android 清单文件添加
WAKE_LOCK
权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
使用 AmbientModeSupport 类支持氛围模式
如需使用 AmbientModeSupport
类,请执行以下操作:
-
创建
FragmentActivity
的子类,即创建其任一子类。 -
实现
AmbientCallbackProvider
接口,如以下示例所示。替换getAmbientCallback()
方法,以提供对来自 Android 系统的氛围事件做出反应所需的回调。在后面的一个步骤中,您将创建自定义回调类。Kotlin
class MainActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackProvider { ... override fun getAmbientCallback(): AmbientModeSupport.AmbientCallback = MyAmbientCallback() ... }
Java
public class MainActivity extends AppCompatActivity implements AmbientModeSupport.AmbientCallbackProvider { ... @Override public AmbientModeSupport.AmbientCallback getAmbientCallback() { return new MyAmbientCallback(); } ... }
-
在
onCreate()
方法中,通过调用AmbientModeSupport.attach(FragmentActivity)
来启用氛围模式。此方法会返回AmbientModeSupport.AmbientController
。您可以通过该控制器检查回调之外的氛围状态。您可能需要保留对AmbientModeSupport.AmbientController
对象的引用:Kotlin
class MainActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackProvider { ... /* * Declare an ambient mode controller, which will be used by * the activity to determine if the current mode is ambient. */ private lateinit var ambientController: AmbientModeSupport.AmbientController ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) ... ambientController = AmbientModeSupport.attach(this) } ... }
Java
public class MainActivity extends AppCompatActivity implements AmbientModeSupport.AmbientCallbackProvider { ... /* * Declare an ambient mode controller, which will be used by * the activity to determine if the current mode is ambient. */ private AmbientModeSupport.AmbientController ambientController; ... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ... ambientController = AmbientModeSupport.attach(this); } ... }
-
创建一个扩展
AmbientCallback
类的内部类,以便对氛围事件进行操作。此类将成为从您在第 2 步中创建的方法返回的对象,如以下示例所示:Kotlin
private class MyAmbientCallback : AmbientModeSupport.AmbientCallback() { override fun onEnterAmbient(ambientDetails: Bundle?) { // Handle entering ambient mode } override fun onExitAmbient() { // Handle exiting ambient mode } override fun onUpdateAmbient() { // Update the content } }
Java
private class MyAmbientCallback extends AmbientModeSupport.AmbientCallback { @Override public void onEnterAmbient(Bundle ambientDetails) { // Handle entering ambient mode } @Override public void onExitAmbient() { // Handle exiting ambient mode } @Override public void onUpdateAmbient() { // Update the content } }
请查看 GitHub 上的 AlwaysOnKotlin 示例,以了解详细信息和最佳实践。
使用 WearableActivity 类支持氛围模式
对于新项目和现有项目,您可以通过更新项目配置,为 Wear 应用添加氛围模式支持。
创建一个支持氛围模式的 activity
您可以使用
WearableActivity
类在 activity 中启用氛围模式,如下所示:
-
创建扩展
WearableActivity
的 activity。 -
在您的 activity 的
onCreate()
方法中,调用setAmbientEnabled()
方法。
以下代码段展示了如何在 activity 中启用氛围模式:
Kotlin
class MainActivity : WearableActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setAmbientEnabled() ... } }
Java
public class MainActivity extends WearableActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setAmbientEnabled(); ... }
处理模式之间的转换
如果用户在应用显示期间有一段时间未与应用进行互动,或者屏幕被覆盖,系统就会将 activity 切换到氛围模式。
在应用切换到氛围模式后,将 activity 界面更新为更基本的布局以减少耗电量。请使用黑色背景和最简单的白色图形和文本。
为了简化从互动模式到氛围模式的转换,请尽量在屏幕上保持相似的项目布局。
注意:在氛围模式下,应停用屏幕上的所有互动元素,如按钮。
当 activity 切换到氛围模式时,系统会调用氛围回调的 onEnterAmbient()
方法。以下代码段展示了如何在系统切换到氛围模式后将文本颜色更改为白色并停用抗锯齿功能:
Kotlin
override fun onEnterAmbient(ambientDetails: Bundle?) { super.onEnterAmbient(ambientDetails) stateTextView.setTextColor(Color.WHITE) stateTextView.paint.isAntiAlias = false }
Java
@Override public void onEnterAmbient(Bundle ambientDetails) { super.onEnterAmbient(ambientDetails); stateTextView.setTextColor(Color.WHITE); stateTextView.getPaint().setAntiAlias(false); }
当用户点按屏幕或抬起手腕时,activity 会从氛围模式切换回互动模式。系统会调用 onExitAmbient()
方法。您可以替换此方法以更新界面布局,让您的应用以全彩色互动状态显示。
以下代码段展示了如何在系统切换到互动模式后将文本颜色更改为绿色并启用抗锯齿:
Kotlin
override fun onExitAmbient() { super.onExitAmbient() stateTextView.setTextColor(Color.GREEN) stateTextView.paint.isAntiAlias = true }
Java
@Override public void onExitAmbient() { super.onExitAmbient(); stateTextView.setTextColor(Color.GREEN); stateTextView.getPaint().setAntiAlias(true); }
在氛围模式下更新内容
在氛围模式下,您可以更新屏幕以向用户显示新信息,但您必须小心地在显示更新与电池续航时间之间取得平衡。在氛围模式下,更新屏幕的频率最好不要超过每分钟一次。
如需更新应用内容,请替换氛围回调中的
onUpdateAmbient()
方法:
Kotlin
override fun onUpdateAmbient() { super.onUpdateAmbient() // Update the content }
Java
@Override public void onUpdateAmbient() { super.onUpdateAmbient(); // Update the content }
在氛围模式下,更新 Wear 应用的频率最好不要超过每分钟一次。如果应用需要更频繁地进行更新,请使用 AlarmManager
对象唤醒处理器,并更频繁地更新屏幕。
如需实现一个在氛围模式下更频繁地更新内容的闹钟,请按以下步骤操作:
- 准备闹钟管理器。
- 设置更新频率。
- 检查设备当前是否处于氛围模式,并在 activity 切换到氛围模式时安排下一次更新时间。
- 当 activity 切换到互动模式或停止时,取消闹钟。
注意:闹钟管理器可能会在触发时创建 activity 的新实例。为防止出现这种行为,请在清单中使用 android:launchMode="singleInstance"
参数声明您的 activity。
下面几部分将详细介绍这些步骤。
准备闹钟管理器
闹钟管理器会启动一个 PendingIntent
,用来更新屏幕并安排下次闹钟时间。以下示例展示了如何在 activity 的 onCreate()
方法中声明闹钟管理器和待定 intent:
Kotlin
// Action for updating the display in ambient mode, per our custom refresh cycle private const val AMBIENT_UPDATE_ACTION = "com.your.package.action.AMBIENT_UPDATE" ... private lateinit var ambientUpdateAlarmManager: AlarmManager private lateinit var ambientUpdatePendingIntent: PendingIntent private lateinit var ambientUpdateBroadcastReceiver: BroadcastReceiver override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setAmbientEnabled() ambientUpdateAlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager ambientUpdatePendingIntent = Intent(AMBIENT_UPDATE_ACTION).let { ambientUpdateIntent -> PendingIntent.getBroadcast(this, 0, ambientUpdateIntent, PendingIntent.FLAG_UPDATE_CURRENT) } ambientUpdateBroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { refreshDisplayAndSetNextUpdate() } } ... }
Java
// Action for updating the display in ambient mode, per our custom refresh cycle private static final String AMBIENT_UPDATE_ACTION = "com.your.package.action.AMBIENT_UPDATE"; private AlarmManager ambientUpdateAlarmManager; private PendingIntent ambientUpdatePendingIntent; private BroadcastReceiver ambientUpdateBroadcastReceiver; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setAmbientEnabled(); ambientUpdateAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent ambientUpdateIntent = new Intent(AMBIENT_UPDATE_ACTION); ambientUpdatePendingIntent = PendingIntent.getBroadcast( this, 0, ambientUpdateIntent, PendingIntent.FLAG_UPDATE_CURRENT); ambientUpdateBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { refreshDisplayAndSetNextUpdate(); } }; ... }
使用 onResume()
和 onPause()
注册和取消注册广播接收器:
Kotlin
override fun onResume() { super.onResume() IntentFilter(AMBIENT_UPDATE_ACTION).also { filter -> registerReceiver(ambientUpdateBroadcastReceiver, filter) } } override fun onPause() { super.onPause() unregisterReceiver(ambientUpdateBroadcastReceiver) ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) }
Java
@Override public void onResume() { super.onResume(); IntentFilter filter = new IntentFilter(AMBIENT_UPDATE_ACTION); registerReceiver(ambientUpdateBroadcastReceiver, filter); ... } @Override public void onPause() { super.onPause(); unregisterReceiver(ambientUpdateBroadcastReceiver); ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); ... }
更新屏幕并安排数据更新
在此示例 activity 中,闹钟管理器在氛围模式下每 20 秒触发一次。当计时器开始计时的时候,闹钟就会触发 intent 来更新屏幕,然后设置下次更新的延迟时间。
以下示例展示了如何更新屏幕上的信息并为下次更新设置闹钟:
Kotlin
// Milliseconds between waking processor/screen for updates private val AMBIENT_INTERVAL_MS: Long = TimeUnit.SECONDS.toMillis(20) ... private fun refreshDisplayAndSetNextUpdate() { if (isAmbient) { // Implement data retrieval and update the screen for ambient mode } else { // Implement data retrieval and update the screen for interactive mode } val timeMs: Long = System.currentTimeMillis() // Schedule a new alarm if (isAmbient) { // Calculate the next trigger time val delayMs: Long = AMBIENT_INTERVAL_MS - timeMs % AMBIENT_INTERVAL_MS val triggerTimeMs: Long = timeMs + delayMs ambientUpdateAlarmManager.setExact( AlarmManager.RTC_WAKEUP, triggerTimeMs, ambientUpdatePendingIntent) } else { // Calculate the next trigger time for interactive mode } }
Java
// Milliseconds between waking processor/screen for updates private static final long AMBIENT_INTERVAL_MS = TimeUnit.SECONDS.toMillis(20); private void refreshDisplayAndSetNextUpdate() { if (isAmbient()) { // Implement data retrieval and update the screen for ambient mode } else { // Implement data retrieval and update the screen for interactive mode } long timeMs = System.currentTimeMillis(); // Schedule a new alarm if (isAmbient()) { // Calculate the next trigger time long delayMs = AMBIENT_INTERVAL_MS - (timeMs % AMBIENT_INTERVAL_MS); long triggerTimeMs = timeMs + delayMs; ambientUpdateAlarmManager.setExact( AlarmManager.RTC_WAKEUP, triggerTimeMs, ambientUpdatePendingIntent); } else { // Calculate the next trigger time for interactive mode } }
安排下次闹钟时间
通过替换 onEnterAmbient()
方法和 onUpdateAmbient()
方法,安排更新屏幕的闹钟时间,如以下示例所示:
Kotlin
override fun onEnterAmbient(ambientDetails: Bundle?) { super.onEnterAmbient(ambientDetails) refreshDisplayAndSetNextUpdate() } override fun onUpdateAmbient() { super.onUpdateAmbient() refreshDisplayAndSetNextUpdate() }
Java
@Override public void onEnterAmbient(Bundle ambientDetails) { super.onEnterAmbient(ambientDetails); refreshDisplayAndSetNextUpdate(); } @Override public void onUpdateAmbient() { super.onUpdateAmbient(); refreshDisplayAndSetNextUpdate(); }
注意:在本例中,每当需要更新屏幕时,就会调用 refreshDisplayAndSetNextUpdate()
方法。如需查看关于何时调用此方法的更多示例,请参阅 GitHub 上的 AlwaysOnKotlin 示例。
取消闹钟
当设备切换到互动模式时,在 onExitAmbient()
方法中取消闹钟:
Kotlin
override fun onExitAmbient() { super.onExitAmbient() ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) }
Java
@Override public void onExitAmbient() { super.onExitAmbient(); ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); }
当用户退出或停止 activity 时,在 activity 的 onDestroy()
方法中取消闹钟:
Kotlin
override fun onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) super.onDestroy() }
Java
@Override public void onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); super.onDestroy(); }