안드로이드 프로그래밍[Kotiln Code]/안드로이드 부분 함수(권한얻기,인텐트, 데이터바인딩)

[Kotiln] 안드로이드 죽지 않는 서비스 사용하기 (라이프 싸이클 이용)

훈츠 2020. 4. 8. 01:29
반응형

안녕하세요. 훈츠 입니다. 안드로이드의 죽지 않는 서비스 구현 하는 방법 입니다. 앱의 런닝 상태인지, 혹은 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)
  • 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

실행 화면

https://youtu.be/8F26IBAp8yk


onTrimMemory 콜백 


코드 공유

https://github.com/rain2002kr/Immortal_service.git

 

rain2002kr/Immortal_service

라이프싸이클이용한 죽지않는 서비스. Contribute to rain2002kr/Immortal_service development by creating an account on GitHub.

github.com

 

반응형