Jetpack의 Navigation을 사용하여 화면 이동을 했을 때
Activity, Fragment가 정확히 어떤 타이밍에 어떻게 lifecycle이 순환하는지 확인한다
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
필요한 종속 항목 선언
https://developer.android.com/jetpack/androidx/releases/lifecycle#kotlin
def lifecycle_version = "2.6.0-alpha01"
def arch_version = "2.1.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// ViewModel utilities for Compose
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
Activity
Activity에서 화면 이동을 했을 때 Acticity에서 라이프사이클이 어떻게 변화하는지 알아본다
[MainActivity의 전체 코드]
package com.example.selftest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.example.selftest.databinding.ActivityMainBinding
import kotlinx.coroutines.launch
import timber.log.Timber
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
Timber.plant(MyTimber())
Timber.d("Activity onCreate")
// lifecycleScope의 상태 변화에 따른 log 출력
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED){
Timber.d("lifecycle Created")
}
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED){
Timber.d("lifecycle Started")
}
}
lifecycleScope.launch{
repeatOnLifecycle(Lifecycle.State.RESUMED){
Timber.d("lifecycle Resumed")
}
}
}
// Activity의 lifecycle이 변할 때마다 log 출력하기
override fun onStart() {
super.onStart()
Timber.d("Activity onStart")
}
override fun onDestroy() {
super.onDestroy()
Timber.d("Activity onDestroy")
}
override fun onResume() {
super.onResume()
Timber.d("Activity onResume")
}
override fun onPause() {
super.onPause()
Timber.d("Activity onPause")
}
}
각 lifecycle이 시작될 때 로그를 남기도록 했다
1. 처음 실행했을 때 라이프 사이클 변화
- 기본적으로 각각의 override 함수가 먼저 호출되고 그 다음에 각각의 상태에 대한 lifecycleScope가 호출된다
- onCreate -> onStart -> onResume
2. 현재 실행중인 앱 확인 화면(네모 버튼)으로 갔다가 돌아왔을 때 라이프 사이클 변화
- 이 때는 lifecycle에 아무런 영향을 끼치지 않는다
3. Home 화면으로 갔다가 돌아왔을 때 라이프 사이클 변화
- (홈으로 이동) -> onPause -> (돌아옴) -> onStart ->onResume
4. 완전히 다른 화면을 봤다가 돌아왔을 때 라이프 사이클 변화
- onPause -> onStart -> onResume
단, 지금 코드처럼 하나의 lifecycleScope에 각각 repeatOnLifecycle로 출력한 것이 아니라 lifecycleScope.launchWhenCreated { }로 지정하면 딱 한 번만 출력한다
5. 결론
Activity의 lifecycle이 먼저 출력되고 그 다음에 lifecycleScope의 lifecycle이 출력된다
Fragment
Fragment에서 화면 이동을 했을 때 라이프 사이클의 변화를 알아본다
주로 Fragment에서 발생하는 문제는 다른 Fragment에서 돌아왔을 때 observe 하고 있던 데이터를 다시 불러와서 같은 데이터를 2번 set 하는 문제가 많다 lifecycle을 확인하고 이를 방지하기 위핸 대책을 생각해본다
테스트 과정
- FirstFragment, SecondFragment 이렇게 2개의 프래그먼트를 만든다
- FirstFragment에만 라이프 사이클을 알 수 있게 로그를 달아 놓는다
- FirstFragment에서 SecondFragment로 이동했다가 다시 FirstFragment로 돌아온다
- 돌아오는 과정에서 라이프 사이클이 어떻게 변화하는지 확인한다
- 프래그먼트 이동은 navigation을 사용한다
[FirstFragment의 전체 코드]
class FirstFragment : Fragment() {
private lateinit var binding: FragmentFirstBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentFirstBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Timber.d("FirstFragment onViewCreated")
binding.nextFragment.setOnClickListener {
val action = FirstFragmentDirections.actionFirstFragmentToSecondFragment()
findNavController().navigate(action)
}
}
// fragment의 lifecyle 변화에 따른 log 출력
override fun onStart() {
super.onStart()
Timber.d("FirstFragment onStart")
}
override fun onResume() {
super.onResume()
Timber.d("FirstFragment onResume")
}
override fun onPause() {
super.onPause()
Timber.d("FirstFragment onPause")
}
override fun onStop() {
super.onStop()
Timber.d("FirstFragment onStop")
}
override fun onDestroy() {
super.onDestroy()
Timber.d("FirstFragment onDestroy")
}
}
1. 첫 번째 프래그먼트를 열었을 때 라이프 사이클 변화
- onViewCreated -> onStart -> onResume
2. Navigation을 사용하여 첫 번째 프래그먼트에서 두 번째 프래그먼트로 이동했을 때 라이프 사이클 변화
- graph로 이동했을 때는 이전 fragment가 destroy되지 않고 stop 상태에 머물러 있음
- onPause -> onStop
3. Navigation을 사용하여 두 번째 프래그먼트에서 첫 번째 프래그먼트로 돌아왔을 때 라이프 사이클 변화
- destroy는 되지 않았지만 onViewCreated부터 다시 실행된다
- onViewCreated -> onStart -> onResume
4. 액티비티를 완전히 닫았을 때 라이프 사이클 변화
- Activity를 완전히 닫아야 Fragment가 Destroy된다
- onPause -> onStop -> onDestroy
각 화면에 따른 lifecycle의 정리
- Activity는 lifecycle이 먼저 출력되고 그 다음에 lifecycleScope의 lifecycle이 출력된다
- Activity에서 Home 화면으로 갔다가 돌아왔을 때는 onPause -> onStart ->onResume
- Activity에서 완전히 다른 화면을 봤다가 돌아왔을 때는 onPause -> onStart -> onResume
- Fragment에서 Navigation을 사용하여 다른 프래그먼트로 이동했을 때는 onPause -> onStop
- Fragment에서 Navigation을 사용하여 다시 돌아왔을 때는 onViewCreated -> onStart -> onResume
- Fragment에서 Activity를 닫았을 때 onPause -> onStop -> onDestroy
안드로이드 MVVM 아키텍처란 무엇인가 필요성과 그 배경
안드로이드 MVVM 아키텍처 MVC vs MVP vs MVVM 비교 MVVM의 탄생 이유 및 필요성 MVVM 구현 방법 MVC : View와 Controller를 Activity, Fragment에서 담당 MVC 패턴의 경우 그림과 같이 View와 Controller가 연결되어 있습
android-developer.tistory.com
리사이클러뷰의 생명주기 분석 및 메모릭의 원인
리사이클러뷰의 라이프 사이클 (화면에 보여지기까지의 순서) onAttachedToRecyclerView - 리사이클러뷰를 화면에 붙임 onCreateViewHolder - 홀더를 생성 onBindViewHolder - 홀더와 뷰를 바인딩 onViewAttachedToWindow
android-developer.tistory.com
안드로이드 WorkManager는 왜 필요하고 어디서 쓰면될까?
안드로이드 코틀린 WorkManager는 어디서 사용하고 어떻게 사용하면될까? WorkManager는 왜 필요한가? 다른 백그라운드 처리들과의 차이 WorkManager는 어디에 사용하면될까? WorkManager는 어떻게 사용할 수
android-developer.tistory.com
안드로이드 MVVM을 사용하기 위한 필수 요소 AAC란 무엇인가?
기존에 사용하던 MVVM을 좀 더 간편하게 좀 더 정확하게 사용하기 위해 나온 것이 AAC이다. 즉, AAC란 아키텍쳐가 아니라 MVVM을 좀 더 잘 사용하기 위한 도구라고 생각하면 쉽다. 이전에 MVVM이란 무
android-developer.tistory.com
안드로이드 매니페스트(AndroidManifest)의 역할은 무엇일까
안드로이드 매니페스트 파일은 무엇일까? 앱 구성 요소(Activity, Broadcast, Service, Provider)를 정의한 파일 앱이 요구하는 모든 권한을 식별 앱이 요구하는 최소 API을 선언 앱에서 요구하는 하드웨어
android-developer.tistory.com
'안드로이드(kotlin)' 카테고리의 다른 글
registerForActivityResult 사용 방법과 startActivityForResult가 Deprecated된 이유 (2) | 2023.01.07 |
---|---|
리사이클러뷰의 생명주기 분석 및 메모릭의 원인 (0) | 2023.01.05 |
LicenseToolsPlugin을 사용해서 자동으로 라이센스 공개하기 (1) | 2022.12.22 |
안드로이드(Kotlin)를 SOLID로 설계하기 (0) | 2022.12.19 |
Firebase의 analytics로 DebugView 쓰기 (0) | 2022.12.18 |
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
댓글