카카오톡과 같은 메이저 앱들의 경우 위와 같이 앱 내에서의 잠금 기능을 볼 수가 있습니다.
이를 구현하기 위해 각 Base activity마다 값을 주고받으며 onStart에서 띄우게 할 수 있지만
결국 잠금 화면이 나타나는 경우는 해당 프로세스인 앱이 Background에서 Foreground로 진입할 때 뿐입니다.
이를 이용해 앱 Lifecycle을 감지하는 ProcessLifecycleOwner를 사용하여 처리가 가능합니다.
ProcessLifecycle이란 일반적인 Activity에서 override 하는 Lifecycle과 달리 프로세스 관점에서 생명주기를 관리할 수 있게 하는 클래스입니다.
먼저 ProcessLifecycle을 사용하기 위해 build.gradle 파일에 다음과 같이 추가하여 종속성을 추가합니다.
dependencies{
...
implementation 'androidx.lifecycle:lifecycle-process:2.4.1'
...
}
다음과 같이 LifecycleEventObserver를 상속받아서 프로세스의 생명 주기를 확인 및 잠금 화면을 실행할 수 있습니다.
class MyProcessLifecycle(val context: Context): LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.ON_RESUME) {
Log.d(TAG,"lifecycle : on resume")
} else if (event == Lifecycle.Event.ON_PAUSE) {
Log.d(TAG,"lifecycle : on pause")
}
// TODO : start lock screen activity
// context.startActivity(Intent(context,LockActivity::class.java))
}
}
ProcessLifecycleOwner.get().lifecycle.addObserver(MyProcessLifecycle(applicationContext))
하지만 여기서 이벤트 등록시 새 객체를 넣어주면 구현에 따라 이벤트가 중복 등록이 되어
잠금화면이 여러번 실행될 가능성이 있습니다.
다음과 같이 MyProcessLifecycle을 싱글톤으로 생성해서 이벤트 등록시 같은 객체임을 보장합니다.
class MyProcessLifecycle private constructor(): LifecycleEventObserver {
companion object {
private var instance: MyProcessLifecycle? = null
private lateinit var context: Context
fun getInstance(_context: Context): MyProcessLifecycle {
return instance ?: synchronized(this) {
instance ?: MyProcessLifecycle().also {
context = _context
instance = it
}
}
}
}
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.ON_RESUME) {
Log.d(TAG,"lifecycle : on resume")
} else if (event == Lifecycle.Event.ON_PAUSE) {
Log.d(TAG,"lifecycle : on pause")
}
// TODO : start lock screen activity
// context.startActivity(Intent(context,LockActivity::class.java))
}
}
ProcessLifecycleOwner.get().lifecycle.addObserver(MyProcessLifecycle.getInstance(applicationContext))
하지만 이는 context를 static 변수로 설정하기 때문에 다음과 같은 메모리 누수 경고가 뜹니다.
Do not place Android context classes in static fields (static reference to MyProcessLifecycle which has field context pointing to Context); this is a memory leak
또한 위와 같은 방법으로는 이벤트의 동작 시점에따라 본래의 Activity보다 잠금화면이 먼저 실행되어서
잠금 화면 위에 잠금 화면 이후에 실행될 Activity가 그려질 가능성이 존재합니다.
이에 대해서는 Broadcast를 이용하는 방법등이 있겠지만 간단하게 구현할 수 있는 방법으로 준비했습니다.
https://developer.android.com/reference/android/arch/lifecycle/ProcessLifecycleOwner