사용자가 계속 볼 수 있는 Wear OS 앱이 있습니다.
Android 버전 5.1 이상을 실행하는 Wear OS 기기를 사용하면 배터리 전원을 절약하면서 앱을 포그라운드에 유지할 수 있습니다. Wear OS 앱은 시계가 저전력(대기) 모드일 때 시계에 표시되는 내용을 제어할 수 있습니다. 대기 모드와 대화형 모드에서 모두 실행되는 Wear 앱을 상시 사용 설정 앱이라고 합니다.
이러한 앱을 사용하면 조깅하는 사용자가 시계를 보면서 달린 거리와 소요 시간을 확인할 수 있습니다. 어떤 사용자는 쇼핑 목록을 기록하고, 쇼핑하면서 목록에 있는 항목을 빠르게 확인할 수 있습니다.
앱을 계속 표시하면 배터리 수명에 영향을 미치므로, 이 기능을 앱에 추가할 때는 그 영향을 신중하게 고려해야 합니다.
중요:
Android 지원 라이브러리 27.1.0 버전에서는 WearableActivity
클래스 대신 AmbientModeSupport
클래스를 사용하는 새로운 방법으로 대기 모드를 지원할 수 있습니다.
새롭고 선호도 높은 방법을 사용하여 대기 모드를 지원할지 또는 WearableActivity 클래스를 확장할지 결정할 수 있습니다.
참고:
AmbientMode
클래스는 지원 중단되었으며 AmbientModeSupport
클래스로 대체되었습니다.
다음 관련 리소스를 참조하세요.
프로젝트 구성
대기 모드를 지원하려면 Android SDK를 업데이트하고 개발 프로젝트를 구성해야 합니다. 필요한 변경 작업을 실행하려면 다음 단계를 따르세요.
- 웨어러블 앱 만들기 및 실행 페이지의 구성을 기준으로 프로젝트를 만들거나 업데이트합니다.
- Android 매니페스트 파일에
WAKE_LOCK
권한을 추가합니다.
<uses-permission android:name="android.permission.WAKE_LOCK" />
AmbientModeSupport 클래스를 사용한 대기 모드
AmbientModeSupport
클래스를 사용하여 대기 모드를 지원하면 다음과 같은 이점이 있습니다.
-
프래그먼트용 기능인 Android 지원 라이브러리의
Activity
서브클래스(예:FragmentActivity
) 사용 가능 - 수명 주기 인식 아키텍처 구성요소 활용
- Google 로그인 지원 향상
AmbientModeSupport
클래스를 사용하려면 FragmentActivity
서브클래스 중 하나를 확장하거나 FragmentActivity 자체를 확장하고 제공자 인터페이스를 구현합니다. 그러면 이 인터페이스를 사용하여 대기 모드 업데이트를 수신 대기할 수 있습니다.
참고:
AmbientModeSupport.attach(FragmentActivity)
메서드는 제공된 FragmentActivity
클래스 또는 서브클래스에 헤드리스 프래그먼트를 연결하며, 이후 FragmentManager.getFragments()
호출에서 어떤 방식으로도 사용되지 않는 이 프래그먼트의 참조를 반환합니다.
아래에서는 AmbientModeSupport
클래스의 일반적인 사용을 설명합니다.
-
FragmentActivity
클래스 중 하나의 서브클래스를 만듭니다. -
아래 예제와 같이
AmbientCallbackProvider
인터페이스를 구현합니다.getAmbientCallback()
메서드를 재정의하여 Android 시스템의 대기 이벤트에 반응하는 데 필요한 콜백을 제공합니다. 4단계에서 맞춤 콜백 클래스를 만듭니다.Kotlin
class MainActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackProvider { … override fun getAmbientCallback(): AmbientModeSupport.AmbientCallback = MyAmbientCallback() … }
자바
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) } ... }
자바
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 } }
자바
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 } }
자세한 내용과 권장사항은 AlwaysOn 샘플을 참조하세요.
WearableActivity 클래스를 사용한 대기 모드
신규 및 기존 프로젝트의 경우, 프로젝트 구성을 업데이트하여 Wear 앱에 대기 모드 지원을 추가할 수 있습니다.
대기 모드를 지원하는 활동 만들기
WearableActivity
클래스를 사용하여 활동에서 대기 모드를 사용 설정할 수 있습니다.
-
WearableActivity
를 확장하는 활동을 생성합니다. -
활동의
onCreate()
메서드에서setAmbientEnabled()
메서드를 호출합니다.
다음과 같이 활동에서 대기 모드를 사용 설정합니다.
Kotlin
class MainActivity : WearableActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setAmbientEnabled() ... } }
자바
public class MainActivity extends WearableActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setAmbientEnabled(); ... }
모드 간 전환 처리
사용자가 앱이 표시된 상태에서 일정 기간 앱과 상호작용하지 않거나 사용자가 손바닥으로 화면을 덮으면 시스템이 활동을 대기 모드로 전환합니다. 앱이 대기 모드로 전환되면, 활동 UI를 보다 기본적인 레이아웃으로 업데이트하여 전력 소비를 줄입니다. 최소한의 흰색 그래픽과 텍스트가 있는 검은색 배경을 사용해야 합니다. 사용자가 대화형 모드에서 대기 모드로 쉽게 전환할 수 있도록 화면의 항목 배치를 비슷하게 유지합니다. 대기 화면에 콘텐츠를 표시하는 방법에 대한 자세한 내용은 Wear OS의 시계 모드 디자인 가이드를 참조하세요.
하드웨어 버튼이 없는 기기에서 앱을 실행하는 경우에는 손바닥으로 화면을 덮어도 앱이 대기 모드로 전환되지 않습니다. 대신, 앱이 종료되고 홈 화면이 표시됩니다. 이 동작은 사용자가 앱을 정상적으로 종료할 수 있도록 하기 위한 것입니다. 그러나 화면이 타임아웃되면 이러한 기기도 대기 모드로 전환됩니다.
참고: 대기 모드에서는 버튼과 같은 화면의 대화형 요소를 중지합니다. 상시 사용 설정 앱의 사용자 상호작용을 설계하는 방법에 대한 자세한 내용은 Wear OS의 앱 구조 디자인 가이드를 참조하세요.
활동이 대기 모드로 전환되면 시스템이 웨어러블 활동에서 onEnterAmbient()
메서드를 호출합니다. 다음 코드 스니펫은 시스템이 대기 모드로 전환된 후 텍스트 색상을 흰색으로 변경하고 앤티앨리어싱을 중지하는 방법을 보여줍니다.
Kotlin
override fun onEnterAmbient(ambientDetails: Bundle?) { super.onEnterAmbient(ambientDetails) stateTextView.setTextColor(Color.WHITE) stateTextView.paint.isAntiAlias = false }
자바
@Override public void onEnterAmbient(Bundle ambientDetails) { super.onEnterAmbient(ambientDetails); stateTextView.setTextColor(Color.WHITE); stateTextView.getPaint().setAntiAlias(false); }
사용자가 화면을 탭하거나 손목을 위로 올리면 활동이 대기 모드에서 대화형 모드로 전환됩니다. 시스템에서
onExitAmbient()
메서드를 호출합니다. 이 메서드를 재정의하여 앱이 대화형 칼라 상태로 표시되도록 UI 레이아웃을 업데이트합니다.
다음 코드 스니펫은 시스템이 대화식 모드로 전환될 때 텍스트 색상을 녹색으로 변경하고 앤티앨리어싱을 사용 설정하는 방법을 보여줍니다.
Kotlin
override fun onExitAmbient() { super.onExitAmbient() stateTextView.setTextColor(Color.GREEN) stateTextView.paint.isAntiAlias = true }
자바
@Override public void onExitAmbient() { super.onExitAmbient(); stateTextView.setTextColor(Color.GREEN); stateTextView.getPaint().setAntiAlias(true); }
대기 모드의 콘텐츠 업데이트
대기 모드에서 화면을 새로운 사용자 정보로 업데이트할 수 있지만, 화면 업데이트와 배터리 수명 간에 적절한 균형을 유지해야 합니다. 대기 모드에서는 1분에 한 번만 화면을 업데이트하도록
onUpdateAmbient()
메서드를 재정의하는 것이 좋습니다. 앱을 자주 업데이트해야 하는 경우 배터리 수명과 업데이트 빈도 간에 장단점이 있음을 고려합니다. 배터리를 절약하려면 업데이트 빈도가 10초마다 한 번 이하여야 합니다. 그러나 실제로 앱을 업데이트하는 빈도는 이보다 더 낮아야 합니다.
1분에 한 번 업데이트
배터리 전원을 보존하기 위해, 대부분의 Wear 앱은 대기 모드에서 화면을 자주 업데이트하지 않아야 합니다. 이 모드에서는 1분당 한 번 화면을 업데이트하도록 앱을 설계하는 것이 좋습니다. 이러한 권장 빈도로 화면을 업데이트할 수 있도록 시스템에서는 콜백 메서드 onUpdateAmbient()
를 제공합니다.
앱 콘텐츠를 업데이트하려면 웨어러블 활동에서 onUpdateAmbient()
메서드를 재정의합니다.
Kotlin
override fun onUpdateAmbient() { super.onUpdateAmbient() // Update the content }
자바
@Override public void onUpdateAmbient() { super.onUpdateAmbient(); // Update the content }
더 자주 업데이트
권장사항은 아니지만 대기 모드의 Wear 앱을 1분당 한 번 이상 업데이트할 수 있습니다. 더 자주 업데이트해야 하는 앱의 경우 AlarmManager
객체를 사용하여 프로세서의 절전 모드를 해제하고 화면을 더 자주 업데이트할 수 있습니다.
대기 모드에서 콘텐츠를 자주 업데이트하는 경보를 구현하려면 다음 단계를 따르세요.
- 경보 관리자를 준비합니다.
- 업데이트 빈도를 설정합니다.
- 활동이 대기 모드로 전환되거나 현재 대기 모드일 때 다음 업데이트 일정을 예약합니다.
- 활동이 대화형 모드로 전환되거나 활동이 중지되면 경보를 취소합니다.
참고: 경보 관리자가 트리거되면 활동의 새 인스턴스를 만들 수도 있습니다. 이러한 상황을 방지하려면 매니페스트에서 android:launchMode="singleInstance"
매개변수를 사용하여 활동이 선언되도록 하세요.
다음 섹션에서 각 단계를 자세히 설명합니다.
경보 관리자 준비
경보 관리자는 화면을 업데이트하고 다음 경보 일정을 예약하는 대기 중인 인텐트를 시작합니다. 다음 예제에서는 활동의 onCreate()
메서드에서 경보 관리자 및 대기 중인 인텐트를 선언하는 방법을 보여줍니다.
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() } } ... }
자바
// 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()
에서 broadcast receiver를 등록/등록 취소해야 합니다.
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) }
자바
@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); ... }
화면 업데이트 및 데이터 업데이트 일정 예약
이 예제 활동에서는 경보 관리자가 대기 모드에서 20초마다 트리거됩니다. 타이머가 소리를 내면 경보가 화면 업데이트 인텐트를 트리거한 후 다음 업데이트에 대한 지연을 설정합니다.
다음 예제에서는 화면의 정보를 업데이트하고 다음 업데이트에 대한 경보를 설정하는 방법을 보여줍니다.
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 } }
자바
// 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() }
자바
@Override public void onEnterAmbient(Bundle ambientDetails) { super.onEnterAmbient(ambientDetails); refreshDisplayAndSetNextUpdate(); } @Override public void onUpdateAmbient() { super.onUpdateAmbient(); refreshDisplayAndSetNextUpdate(); }
참고: 이 예제에서는 화면을 업데이트해야 할 때마다 refreshDisplayAndSetNextUpdate()
메서드가 호출됩니다. 이 메서드를 호출해야 하는 경우에 대한 추가 예제는 AlwaysOn 샘플을 참조하세요.
경보 취소
기기가 대화형 모드로 전환되면 onExitAmbient()
메서드에서 경보를 취소합니다.
Kotlin
override fun onExitAmbient() { super.onExitAmbient() ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) }
자바
@Override public void onExitAmbient() { super.onExitAmbient(); ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); }
사용자가 활동을 종료하거나 중지하면 활동의 onDestroy()
메서드에서 경보를 취소합니다.
Kotlin
override fun onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) super.onDestroy() }
자바
@Override public void onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); super.onDestroy(); }
이전 버전과의 호환성 유지
대기 모드를 지원하는 활동은 Android 5.1(API 수준 22) 이전 버전인 Wear 기기에서 자동으로 일반 활동으로 되돌아갑니다. 이러한 Android 버전의 기기를 지원하기 위해 특별한 앱 코드가 필요한 것은 아닙니다. 기기가 대기 모드로 전환되면, 기기가 홈 화면으로 돌아가고 활동을 종료합니다.
Android 5.1 이전 버전의 기기에서 앱을 설치하거나 업데이트하지 않으려면 다음과 같이 manifest를 업데이트합니다.
<uses-library android:name="com.google.android.wearable" android:required="true" />