Android - PowerManager WakeLock

By JS | Last updated: December 23, 2020

안드로이드는 디바이스가 사용되지 않을 때 배터리가 소모되지 않도록 절전모드로 전환됩니다. 절전모드로 진입하면 화면도 꺼지고 CPU도 멈추게 됩니다.

만약 내 앱의 Background Process에서 시간이 오래 걸리는 작업을 처리하고 있었는데, 절전모드로 진입하였다면 Process가 Sleep 상태에 빠져 아무 일도 하지 않을 수 있습니다. 이럴 때, WakeLock을 이용하여 문제를 해결할 수 있습니다.

WakeLock은 디바이스가 Sleep 상태에 빠지지 않도록 합니다. 작업을 처리하기 전에 WakeLock을 얻고, 모든 작업이 완료된 뒤에 WakeLock을 시스템에 반환하면 작업이 처리되는 중에 CPU가 멈추지 않게 됩니다.

WakeLock 권한

WakeLock을 사용하려면 AndroidManifest에 다음 권한을 추가해야 합니다.

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

앱이 설치되는 동시에 권한을 갖는 Install Permission이기 때문에 Manifest에 선언만 하면 됩니다.

WakeLock 예제

다음은 WakeLock을 이용하여 어떤 작업을 처리하는 예제입니다.

// 1. Aquire wakelock
val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
val wakeLock: PowerManager.WakeLock =
        pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp::MyWakelockTag")
wakeLock.acquire()

// 2. Perform your tasks

// 3. Release wakelock
wakeLock.release()
  1. Background Thread에 오래 걸리는 작업을 하기 전에 WakeLock을 획득해야 합니다. newWakeLock(level, name)으로 WakeLock을 생성할 수 있으며, acquire()를 호출하면 WakeLock을 획득하게 됩니다.
  2. 오래 걸리는 작업을 처리하면 됩니다.
  3. 작업이 모두 완료되었다면 release()로 WakeLock을 반환해야 합니다. 반환하지 않으면 디바이스는 계속 깨어있는 상태가 되어 배터리가 소모됩니다.

WakeLock Level

newWakeLock()의 인자로 전달되는 Level은 다음과 같은 것들이 있습니다.

Flag Value CPU Screen Keyboard
PARTIAL_WAKE_LOCK On Off Off
SCREEN_DIM_WAKE_LOCK On Dim Off
SCREEN_BRIGHT_WAKE_LOCK On Bright Off
FULL_WAKE_LOCK On Bright Bright

Android Developer의 PowerManager의 설명을 정리하였습니다. Deprecated된 FLAG에 대한 내용은 사이트에서 직접 확인하세요.

  • PARTIAL_WAKE_LOCK : screen과 keyboard의 backlight는 꺼지고 CPU는 동작합니다. 사용자가 Power 버튼을 눌러 screen을 꺼도 CPU는 WakeLock이 release될 때까지 동작합니다.
  • SCREEN_DIM_WAKE_LOCK : 이 옵션은 Deprecated되었고, 대신 WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON를 이용하라고 합니다.
  • SCREEN_BRIGHT_WAKE_LOCK : 이 옵션은 Deprecated되었고, 대신 WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON를 이용하라고 합니다.
  • FULL_WAKE_LOCK : 이 옵션은 Deprecated되었고, 대신 WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON를 이용하라고 합니다.

WakeLock Timeout

위의 예제에서는 명시적으로 release()를 호출해야 했습니다. 실수로 release()를 빼먹으면 디바이스는 항상 켜있게 되고 배터리는 빠르게 소모하게 됩니다.

acquire(timeout)를 사용하면 인자로 전달된 시간 뒤에 release()가 호출되어 WakeLock이 자동으로 해제됩니다. 실수로 release()를 호출하지 않는 경우를 예방할 수 있습니다. (timeout의 시간 단위는 millisecond 입니다.)

그렇기 때문에 Timeout은 작업이 처리되는데 예상되는 시간보다 충분히 많은 시간을 넣어주면 좋습니다. 또한, 작업을 마친 후 명시적으로 WakeLock을 해제하도록 구현해야 배터리를 아낄 수 있습니다.

// 1. Aquire wakelock
val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
val wakeLock: PowerManager.WakeLock =
        pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp::MyWakelockTag")
wakeLock.acquire(60 * 1000) // 60 sec

// 2. Perform your tasks

// 3. Release WakeLock
if (wakeLock.isHeld) {
    wakeLock.release()
}
  1. acquire(60 * 1000)으로 60초 뒤에도 WakeLock이 해제되지 않으면 자동으로 해제되도록 Timeout을 설정하였습니다.
  2. 작업을 수행합니다.
  3. 작업이 완료되었을 때 WakeLock을 해제합니다. isHeld()는 WakeLock을 획득하고 있을 때 true를 리턴합니다.

Related Posts

댓글을 보거나 쓰려면 이 버튼을 눌러주세요.
codechachaCopyright ©2019 codechacha