안녕하세요. 훈츠 입니다. 안드로이드의 죽지 않는 서비스 구현 하는 방법 입니다. 앱의 런닝 상태인지, 혹은 UI 가 안보이는 상태인지 APP 이 꺼졌는지 확인할수 있는 방법에 대해 포스팅 합니다.
Android Jetpack - Lifecycle
- Livecycle: Lifecylce을 나타내는 객체입니다.
- LivecycleOwner: Activity객체를 말하며 Lifecycle객체에 액티비티 상태를 제공해줍니다.
- LifecycleObserver: Lifecylce로부터 액티비티 상태변화에 대한 이벤트를 받습니다.
LifecycleOwner, Lifecycle
LifecycleOwner는 Activity를 의미하고, 내부에 Lifecycle을 갖고 있습니다. Lifecycle은 액티비티의 상태를 저장하고 옵저버들에게 상태변화를 알려줍니다.
사용법 정리
- Dependency { lifecycler 추가
- class AppLifecyclerHandler 만들기
- class App : Application(), LifecycleDelegate 상속 하여 만들기
- 상속한 클래스에 함수 오버라이드 해서 구현하기
- class ArchLifecycleApp : Applicatoin(), LifecycleObserver 상속 하여 만들기
- 상속한 클래스에 함수 오버라이드 해서 구현하기 (@annotation 이용)
- @OnLifecycleEvent(Lifecycle.Event.ON_START)
- 상속한 클래스에 함수 오버라이드 해서 구현하기 (@annotation 이용)
- Manifestes 에 android:name ="구현할 클래스 선택" (App 인지 ArchLifecycleApp)
- MyService 만들기
- 이곳에서 시간 지나면 MainActivity를 띄어줌.
Dependency 추가
1
2
3
4
5
6
7
8
9
10
|
//훈스 블로그---------------------------------------------------------------------------------------------------코드//
dependencies {
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
AppLifecycleHandler 클래스 추가
LifeCycleDelegate 를 매개변수로 갖고, Application.ActivityLifecyclerCallBacks 과 ComponentCallbacks2 를 상속 하고 LifeCycleDelegate 인터페이스에 함수를 등록 시켜 놓습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
//훈스 블로그---------------------------------------------------------------------------------------------------코드//
class AppLifecycleHandler(private val lifeCycleDelegate: LifeCycleDelegate)
: Application.ActivityLifecycleCallbacks, ComponentCallbacks2
{
private var appInForeground = false
override fun onActivityPaused(p0: Activity?) { }
override fun onActivityResumed(p0: Activity?)
{
lifeCycleDelegate.onAppForegrounded()
}
override fun onActivityStarted(p0: Activity?)
{
appInForeground = true
}
override fun onActivityDestroyed(p0: Activity?)
{
lifeCycleDelegate.onDestroy()
}
override fun onActivitySaveInstanceState(p0: Activity?, p1: Bundle?) { }
override fun onActivityStopped(p0: Activity?)
{
appInForeground = false
}
override fun onActivityCreated(p0: Activity?, p1: Bundle?) { }
override fun onLowMemory() { }
override fun onConfigurationChanged(p0: Configuration?) { }
override fun onTrimMemory(level: Int)
{
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
appInForeground = false
lifeCycleDelegate.onAppBackgrounded()
}
if (level == ComponentCallbacks2.TRIM_MEMORY_BACKGROUND){
appInForeground = false
}
}
}
interface LifeCycleDelegate {
fun onAppBackgrounded()
fun onAppForegrounded()
fun onDestroy()
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
App 클래스 추가
Application 과 LifeCycleDelegate 를 상속 하여, App 클래스를 만들고, Application 과 LifeCycleDelegate에 인터페이스로 구현된 함수를 오버라이드 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
//훈스 블로그---------------------------------------------------------------------------------------------------코드//
class App : Application(), LifeCycleDelegate {
val TAG :String = "App"
var appInBackGround :Boolean = false
override fun onCreate() {
super.onCreate()
val lifeCycleHandler = AppLifecycleHandler(this)
registerLifecycleHandler(lifeCycleHandler)
}
override fun onAppBackgrounded() {
Log.d(TAG, "App in background")
appInBackGround = true
}
override fun onAppForegrounded() {
Log.d(TAG, "App in foreground")
appInBackGround = false
}
override fun onDestroy() {
Log.d(TAG, "onDestroy")
if(appInBackGround == true) {
val intent = Intent(applicationContext, MyService::class.java)
intent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or
Intent.FLAG_ACTIVITY_CLEAR_TOP
)
intent.putExtra("command", "onAppStoppedRestart")
startService(intent)
}
}
private fun registerLifecycleHandler(lifeCycleHandler: AppLifecycleHandler) {
registerActivityLifecycleCallbacks(lifeCycleHandler)
registerComponentCallbacks(lifeCycleHandler)
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
ArchLifecycleApp 클래스 추가
Application 과 LifeCycleObserver 를 상속 하여, ArchLifecycleApp 클래스를 만들고, Application 과 LifeCycleObserver에 인터페이스로 구현된 함수를 오버라이드 합니다. 이것은 옵저버를 이용한 방식 입니다만, 현재 제가 테스트해본 결과 onDestory() 함수는 잘 구현 되질 않았습니다. 제가 실수 한것이 있다면 댓글 남겨주세요.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
//훈스 블로그---------------------------------------------------------------------------------------------------코드//
/**
* If you are using Android Architecture Components you can use the ProcessLifecycleOwner
* and LifecycleObserver like so (set this class to the app name in the manifest)
* // <application
// android:name=".ArchLifecycleApp"
// ....
*/
class ArchLifecycleApp(): Application(), LifecycleObserver {
val TAG :String = "ArchLifecycleApp"
lateinit var lifeCycle :Lifecycle
override fun onCreate() {
super.onCreate()
lifeCycle = ProcessLifecycleOwner.get().lifecycle
Log.d(TAG, "onCreate")
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
Log.d(TAG, "onStart")
//Log.d(TAG, "App in foreground_Life")
Log.d(TAG, "onStart")
if (lifeCycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
Log.d(TAG, "currentState is greater or equal to INITIALIZED")
}
if (lifeCycle.currentState.isAtLeast(Lifecycle.State.CREATED)) {
Log.d(TAG, "currentState is greater or equal to CREATED")
}
if (lifeCycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
Log.d(TAG, "currentState is greater or equal to STARTED")
}
if (lifeCycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
Log.d(TAG, "currentState is greater or equal to RESUMED")
}
if (lifeCycle.currentState.isAtLeast(Lifecycle.State.DESTROYED)) {
Log.d(TAG, "currentState is greater or equal to DESTROYED")
}
}
//temp
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
Log.d(TAG, "onResume")
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
if (lifeCycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
Log.d(TAG, "currentState is greater or equal to RESUMED")
}
if (lifeCycle.currentState.isAtLeast(Lifecycle.State.DESTROYED)) {
Log.d(TAG, "currentState is greater or equal to DESTROYED")
}
Log.d(TAG, "onDestroy")
}
//temp
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
Log.d(TAG, "onPause")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
if (lifeCycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
Log.d(TAG, "currentState is greater or equal to RESUMED")
}
if (lifeCycle.currentState.isAtLeast(Lifecycle.State.DESTROYED)) {
Log.d(TAG, "currentState is greater or equal to DESTROYED")
}
Log.d(TAG, "onStop")
//Log.d(TAG, "App in background1_Life")
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
Manifests 설정
1
2
3
4
5
6
7
|
//훈스 블로그---------------------------------------------------------------------------------------------------코드//
<application
android:name=".App"
//or android:name=".ArchLifecycleApp"
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
myService 만들기
서비스 실행 되면, 5초 Time delay 후 MainActivity를 call 해줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
//훈스 블로그---------------------------------------------------------------------------------------------------코드//
class MyService : Service() {
val TAG : String ="MyService"
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "onStartCommand()")
if(intent == null){
return Service.START_STICKY
} else {
processCmd(intent)
}
return super.onStartCommand(intent, flags, startId)
}
override fun onCreate() {
super.onCreate()
Log.d(TAG, "onCreate()")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy()")
}
override fun onBind(intent: Intent?): IBinder? {
TODO("Not yet implemented")
Log.d(TAG, "onBind()")
}
fun processCmd(intent:Intent){
val command = intent.getStringExtra("command")
val name = intent.getStringExtra("name")
Log.d(TAG, "processCmd(), $command, $name")
//5초 지연후, MainActivity 띄워 줍니다.
Thread.sleep(5000)
val intent = Intent(applicationContext, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or
Intent.FLAG_ACTIVITY_CLEAR_TOP
)
Log.d(TAG, "call mainActivity()")
startActivity(intent)
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
실행 화면
onTrimMemory 콜백
코드 공유
https://github.com/rain2002kr/Immortal_service.git
'안드로이드 프로그래밍[Kotiln Code] > 안드로이드 부분 함수(권한얻기,인텐트, 데이터바인딩)' 카테고리의 다른 글
[Kotlin] 잡스케쥴 (0) | 2020.04.16 |
---|---|
[Kotiln] 화면 오버레이 권한 획득 (0) | 2020.04.16 |
[Kotiln] 유저가 View 만드는 코드 (0) | 2020.04.07 |
[Kotiln] 앱 띄울때 시스템 UI를 숨기고 전체화면 표시 (0) | 2020.04.07 |
[Kotiln] handler and runnable (0) | 2020.04.07 |