๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐˜ˆ๐˜ฏ๐˜ฅ๐˜ณ๐˜ฐ๐˜ช๐˜ฅ๐˜š๐˜ต๐˜ถ๐˜ฅ๐˜ช๐˜ฐ-๐˜’๐˜ฐ๐˜ต๐˜ญ๐˜ช๐˜ฏ

์•กํ‹ฐ๋น„ํ‹ฐ ์ƒ๋ช…์ฃผ๊ธฐ

 

โœ… ์•กํ‹ฐ๋น„ํ‹ฐ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ ์„ค๋ช…

  • onCreate() : ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์ฒ˜์Œ ์ƒ์„ฑ๋  ๋•Œ ํ˜ธ์ถœ, UI ๊ตฌ์„ฑ, ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™” ๋ฆฌ์Šค๋„ˆ ๋“ฑ๋ก ๋“ฑ์„ ์ˆ˜ํ–‰
  • onResume() : ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ํ™”๋ฉด์— ๋ณด์ด๊ณ , ์‚ฌ์šฉ์ž์™€ ์ƒํ˜ธ์ž‘์šฉ ๊ฐ€๋Šฅํ•ด์งˆ ๋•Œ ํ˜ธ์ถœ, ์•ฑ์ด ํฌ๊ทธ๋ผ์šด๋“œ๋กœ ๋ณต๊ท€ํ• ๋•Œ๋„ ํ˜ธ์ถœ๋จ
  • onPause() : ๋‹ค๋ฅธ ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์•ž์— ๋‚˜ํƒ€๋‚  ๋•Œ ์ž ์‹œ ์ค‘๋‹จ๋˜๋Š” ์‹œ์ ์— ํ˜ธ์ถœ, ํ™”๋ฉด์€ ๋ณด์ด์ง€๋งŒ ์ƒํ˜ธ์ž‘์šฉ์€ ์ œํ•œ๋  ์ˆ˜ ์žˆ์Œ
  • onDestory() : ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์™„์ „๋ฆฌ ์ข…๋ฃŒ๋˜๊ธฐ ์ง์ „์— ํ˜ธ์ถœ, ๋ฆฌ์†Œ์Šค ํ•ด์ œ, ๋ฐฑ์—… ์ €์žฅ ๋“ฑ ์ •๋ฆฌ ์ž‘์—… ์ˆ˜ํ–‰
  • onBackPressed() : ์‚ฌ์šฉ์ž๊ฐ€ ๋’ค๋กœ ๊ฐ€๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ํ˜ธ์ถœ 

 

๐Ÿ” ์ƒ๋ช…์ฃผ๊ธฐ ํ๋ฆ„ ์˜ˆ์‹œ

  1. ์•ฑ ์‹คํ–‰ → onCreate() → onStart() → onResume()
  2. ํ™”๋ฉด ์ž ์‹œ ๋ฒ—์–ด๋‚จ → onPause() → onStop()
  3. ๋‹ค์‹œ ๋Œ์•„์˜ด → onRestart() → onStart() → onResume()
  4. ์•ฑ ์ข…๋ฃŒ → onPause() → onStop() → onDestroy()

โœ” ForeGround vs BackGround

  • ํฌ๊ทธ๋ผ์šด๋“œ : ์•ฑ์ด ์ผœ์ ธ ์žˆ๋Š” ์ƒํƒœ, ์ฆ‰ ์œ ์ €๊ฐ€ ์•ฑ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ์ƒํƒœ
  • ๋ฐฑ๊ทธ๋ผ์šด๋“œ : ์•ฑ์ด ๊บผ์ ธ ์žˆ๊ฑฐ๋‚˜, ํ™ˆ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๋น ์ ธ๋‚˜์˜จ ์ƒํƒœ
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle){}
override fun onActivityDestroyed(activity: Activity){}

 

โœ… ์ง„์ž…/์ดํƒˆ ํŒ๋‹จ ๋กœ์ง 

private var activityTracking = 0 //ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์•กํ‹ฐ๋น„ํ‹ฐ์˜ ์ˆ˜๋ฅผ ์ถ”์ 
private var configCheck = false //๋ณ€๊ฒฝ ์—ฌ๋ถ€ ํ™•์ธ

 companion object{
        var isForeground = true //์ƒํƒœ ์Šค์œ„์น˜
        var doOpenWhenStop = true
}//end of object

override fun onActivityStarted(activity: Activity) {
	if(++activityTracking==1&&!configCheck){
    	isForeground=true
        doOpenWhenStop=true
	}//end of if
}//end of Started

override fun onActivityStopped(activity: Activity) {
	configCheck = activity.isChangingConfigurations
    if (--activityTracking==0&&!configCheck){
		isForeground = false
	}//end of if
}//end of Stopped

 

  • ++ activityTracking : activityTracking ๊ฐ’์„ 1์ฆ๊ฐ€ ์‹œํ‚ค๊ณ  ๊ทธ ๊ฐ’์„ ํ‰๊ฐ€
  • ==1 : ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ 1๊ฐœ ๋ฟ์ด๋ผ๋Š” ์˜๋ฏธ, ์ฆ‰ ํฌ๊ทธ๋ผ์šด๋“œ๋กœ ์ง„์ž…ํ•œ ์‹œ์ 
  • ! configCheck : ๊ตฌ์„ฑ ๋ณ€๊ฒฝ (configuration change) ์ค‘์ธ์ง€ ํŒ๋‹จ
    • ๊ตฌ์„ฑ ๋ณ€๊ฒฝ  : ์•ฑ ๋””์Šคํ”Œ๋ ˆ์ด์Šค ํฌ๊ธฐ, ํ™”๋ฉด ๋ฐฉํ–ฅ, ๊ธ€๊ผด ํฌ๊ธฐ ๋ฐ ๋‘๊ป˜, ์–ธ์–ด ๋“ฑ ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ์œผ๋กœ ์ธํ•ด ๋ฐœ์ƒ
      • ex) ํ™”๋ฉด ํšŒ์ „ ์‹œ ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ destroy → recreate๋จ ์ด๋•Œ๋„ onActivityStopped() → onActivityStarted() ํ˜ธ์ถœ๋˜์ง€๋งŒ, ๊ตฌ์„ฑ ๋ณ€๊ฒฝ์ด๋ฏ€๋กœ configCheck  == true → ๋ฌด์‹œํ•จ
  • ++ activityTracking==1 && ! configCheck , ๊ตฌ์„ฑ ๋ณ€๊ฒฝ์— ์˜ํ•œ ์žฌ์‹œ์ž‘์€ ์ œ์™ธ ์•ฑ์ด ์™„์ „ํ•œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ƒํƒœ์—์„œ ์ƒˆ๋กœ ์‹œ์ž‘๋œ ์ƒํƒœ ์™„์ „ํ•œ True(ํฌ๊ทธ๋ผ์šด๋“œ ์ƒํƒœ) 
์ƒํ™ฉ activityTracking ์กฐ๊ฑด ๋งŒ์กฑ ์—ฌ๋ถ€
์•ฑ์ด ์ฒ˜์Œ ์—ด๋ฆผ 0 → ++ → 1 โœ… true
๋‘ ๋ฒˆ์งธ ์•กํ‹ฐ๋น„ํ‹ฐ ์—ด๋ฆผ 1 → ++ → 2 โŒ false
ํ™”๋ฉด ํšŒ์ „์œผ๋กœ ์žฌ์‹œ์ž‘ 1 → 0 → ++ → 1 โŒ (๊ตฌ์„ฑ ๋ณ€๊ฒฝ ์ค‘์ด๋ฏ€๋กœ configCheck== true)

 

์‹œ์   ์ด๋ฒคํŠธ  activityTracking ์ƒํƒœ
์•ฑ ์ฒ˜์Œ ์‹คํ–‰ A ์‹œ์ž‘ 0 → 1 ํฌ๊ทธ๋ผ์šด๋“œ ์ง„์ž…
๋‹ค๋ฅธ ์•กํ‹ฐ๋น„ํ‹ฐ B ์‹คํ–‰ B ์‹œ์ž‘ 1 → 2 ์œ ์ง€
B ์ข…๋ฃŒ B ์ค‘์ง€ 2 → 1 ์œ ์ง€
A ์ข…๋ฃŒ A ์ค‘์ง€ 1 → 0 ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ง„์ž…

 

override fun onActivityStopped(activity: Activity) {
	configCheck = activity.isChangingConfigurations
    if (--activityTracking==0&&!configCheck){
		isForeground = false
        if(doOpenWhenStop){
        	Handler(Looper.myLooper()!!).postDelayed({
            	if(!isForeground){
                	var actManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        			var appTasks = actManager.appTasks
        			appTasks.firstOrNull()?.moveToFront()
				}//end of if
			},10_000L)//end of handler
		}//end of if
	}//end of if
}//end of Stopped
  • --activityTracking==0&&!configCheck : ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ƒํƒœ ์ง„์ž…
    • Handler : ๋ฉ”์„ธ์ง€๋‚˜ ์ž‘์—…์„ ํŠน์ • ์Šค๋ ˆ๋“œ์˜ ๋ฉ”์‹œ์ง€ ํ์— ๋„ฃ์–ด ์ž‘์—…์„ ์˜ˆ์•ฝ/์ง€์—ฐ ์‹คํ–‰, ์ง€์ •๋œ Looper(๋ฉ”์‹œ์ง€ ๋ฃจํ”„)๋ฅผ ๊ฐ€์ง„ ์Šค๋ ˆ๋“œ์—์„œ ์ž‘์—…์„ ์‹คํ–‰, ์ฆ‰ ํ•ด๋‹น Looper์— ์—ฐ๊ฒฐ๋œ ์Šค๋ ˆ๋“œ์—์„œ ์ž‘์—…์„ ์ฒ˜๋ฆฌ ํ•˜๋Š” ์ฝ”๋“œ
    • Looper.myLooper() : ํ˜„์žฌ ์‹คํ–‰์ค‘์ธ ์Šค๋ ˆ๋“œ์˜ Looper ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜, !!(Null์ด ์•„๋‹˜์„ ํ™•์‹  ๊ฐ•์ œ ์‚ฌ์šฉ)
    • .postDelayed(Runnable, delayMillis) : Runnable(์‹คํ–‰ํ•  ์ฝ”๋“œ), delayMillis(๋Œ€๊ธฐ์‹œ๊ฐ„)
  • 10์ดˆ ํ›„ isForeground ์ƒํƒœ ํ™•์ธ ํ›„ ture ์ผ ๋•Œ ์•ฑ์„ ๋‹ค์‹œ ํฌ๊ทธ๋ผ์šด๋“œ๋กœ ๋Œ์–ด์˜ฌ๋ฆฌ๋Š” ์ž‘์—… ์‹คํ–‰ ์ง€์‹œ 
    • getSystemService(String name) ์•ˆ๋“œ๋กœ์ด๋“œ ์‹œ์Šคํ…œ ์„œ๋น„์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ
    • Context.ACTIVITY_SERVICE : Activity Manager๋ฅผ ์š”์ฒญํ•˜๋Š” ์ƒ์ˆ˜ ํ‚ค 
    • .appTasks : ์•ฑ์—์„œ ์‹คํ–‰ ์ค‘์ธ ์ž‘์—… ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜
    • .firstOrNull?().moveToFront() : ์•ฑ์˜ ๊ฐ€์žฅ ์ฒซ๋ฒˆ ์งธ ์ž‘์—…์„ ๊ฐ€์ ธ์˜จ ํ›„ ํ•ด๋‹น ์ž‘์—…์„ ๋งจ ์•ž์œผ๋กœ ๋ณด์—ฌ์ฃผ๋Š” ์—ญํ•