스탠다드반 2주차 과제를 정리해보았다.
- Activity LifeCycle
- Activity Stack
- Fragment LifeCycle
- Fragment 데이터 전달 방식
액티비티가 생성되고 소멸하기까지의 과정을 말하며 Activity 클래스는 액티비티의 상태를 관측하고 조회할 수 있도록 여러 콜백 함수를 제공한다. 콜백 함수에서 액티비티의 상태가 바뀔 때마다 앱이 어떻게 동작해야 하는지 구현한다.

출처: https://developer.android.com/guide/components/activities/activity-lifecycle?hl=ko#alc
entire lifetime
액티비티가 처음 생성될 때 첫 번째로 호출되는 onCreate()부터 마지막에 종료될때 호출되는 onDestroy()까지를 의미한다. onCreate()는 주로 액티비티를 생성할 때 필요한 전반적인 설정 사항을 작업하고 onDestroy()에서는 남아있는 자원을 해제한다. 백그라운드 스레드를 통해 뒤에서 통신을 하거나 다운로드를 해야 하는 액티비티의 경우 네트워크 스레드 호출은 onCreate()에 스레드 종료는 onDestroy()에 하면 정상적으로 스레드를 실행할 수 있다.
visible lifetime
onStart()가 호출되고나서 onStop()이 호출될 때까지를 의미한다. 해당 기간 동안 사용자는 상호작용 가능 여부와는 상관없이 화면에서 액티비티를 볼 수 있다. 액티비티가 보여지거나 보여지지 않는 등 상황에 따라 여러 번 호출될 수 있으르모 개발자가 적절하게 사용할 수 있지만 onStart()가 실핼되는 시점에는 아직 사용자와 상호작용할 UI는 활성화되지 않는다.
foreground lifetime
onResume() 부터 onPause()까지의 기간을 의미하며 화면에 노출되는 기간을 말한다. 예를 들어 디바이스가 절전모드가 되면 onPause()가 호출되고 다시 켜질 때는 onResume()이 호출된다. 다른 기간보다 이 기간이 제일 많이 갱신되기때문에 onResume()과 onPause()의 내용은 가벼워야 한다.
onCreate() : 액티비티 생성 시 최초로 호출되는 콜백 메소드이며 반드시 구현해야 하므로 UI를 표시하는 setContentView()를 여기서 호출한다. onCreate() 다음 콜백은 항상 onStart()이며 처음 실행된 액티비티는 onCreate() -> onStart() -> onResume() 메소드까지 호출된다.
onStart() : onCreate()가 종료되고 액티비티는 시작 상태로 전환되며 사용자에게 표시된다. 해당 콜백은 액티비티가 foreground로 나오고 상호작용하기 위해 준비하는 작업을 수행한다.
onResume() : 액티비티가 사용자와 상호작용하기 직전 호출된다. onResume() 콜백이 호출된 시점에선 액티비티는 액티비티 스택 맨 위에 위치하며 모든 사용자 입력을 받는다. 대부분의 앱 기능은 onResume() 메소드로 구현한다.
onPause() : 시스템이 이전 액티비티를 실행할 때 호출된다. onPause() 메소드는 액티비티의 데이터를 최종 저장하거나 진행 중이었던 애니메이션을 멈춰서 자원이 누수되지 않도록 한다. onPause() 이후 해당 액티비티가 다시 화면의 맨 앞에 위치할 경우 onResume()이, 아닐 경우 onStop()이 이어서 호출된다.
onStop() : 해당 액티비티가 Activity Stack의 top에서 밀려날 때 호출된다. Activity가 다시 top이 될 때는 onRestart()가, stack 대기열에서 완전히 없어질 땐 onDestroy()가 호출된다.
onRestart() : 중지 상태의 액티비티를 다시 시작할 때 호출되는 콜백 메소드로 액티비티가 중지된 시점부터의 상태를 복원하는 역할을 수행한다. 해당 콜백 뒤에는 항상 onStart() 메소드가 호출된다.
onDestroy() : 액티비티가 제거되기 전에 호출되는 콜백으로 액티비티가 finish() 메서드를 통해 종료되거나 시스템의 판단하에 자동으로 액티비티를 해제하는 두 경우일 때 호출되는데 두 경우를 구분짓고 싶다면 메서드 내부에 isFinishing() 메서드를 추가로 호출하여 분기 처리 할 수 있다.
출처 : https://8iggy.tistory.com/267
https://issell.tistory.com/entry/Activity%EC%99%80Activity%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0
1. AndroidManifest의 lanchMode 이용
activity android:launchMode="설정값"
standard

singleTop

singleTask

singleInstance

adb shell dumpsys activity activities | grep 'Hist #' | grep '주소'
해당 코드를 터미널에 작성해서 사용하면 현재 stack을 확인할 수 있다.
출처 : https://apro-developer.tistory.com/49
https://cjh94.tistory.com/22
<강의자료>

출처 : https://developer.android.com/guide/fragments/lifecycle?hl=ko
onAttach()
: onAttach()는 프래그먼트가 FragmentManager에 추가되고 호스트 액티비티에 연결될 때 호출된다. 이 시점에 프래그먼트가 활성화되고 FragmentManager는 프래그먼트의 생명주기를 관리한다.
onCreate()
: 시스템은 프래그먼트를 생성할때 onCreate()를 호출한다. 구현 내에서 프래그먼트의 기본 요소 중 프래그먼트가 일시정지되거나 중단되었다가 재개되었을 때 유지하고자 하는 것을 초기화해야 한다.
onCreateView()
: 시스템은 프래그먼트가 자신의 UI를 처음으로 그릴 시간이 되면 호출한다. 프래그먼트에 맞는 UI를 그리려면 메서드에서 View를 리턴해야 한다. 이 메서드는 프래그먼트 레이아웃의 루트로 프래그먼트가 UI를 제공하지 않는 경우 null을 반환하면 된다.
onViewCreated()
: onCreateView() 를 통해 반환된 View 객체는 onViewCreated()의 파라미터로 전달되는데 이 시점부터는 프래그먼트의 생명 주기가 INITIALIZED 상태로 업데이트됐기 때문에 View의 초기값을 설정해주거나 RecyclerView나 ViewPager2에 사용할 Adapter 초기화 등을 이곳에서 수행하는 것이 적절하다.
onViewStateRestored()
: onViewStateRestored() 함수는 저장해둔 모든 state 값이 Fragment의 View 계층구조에 복원됐을 때 호출된다. View lifecycle owner 는 이때 INITIALIZED 상태에서 CREATED 상태로 변경됐음을 알린다.
onStart()
: 액티비티에서의 역할과 비슷하다. 사용자에게 프래그먼트가 보이도록 하는 역할이다.
onResume()
: 프래그먼트가 화면에 보여지는 단계로 사용자에게 포커스를 잡은 상태이다. 이때 사용자와의 상호작용이 가능하다.
onPause()
: 시스템이 이 메서드를 호출하는 것은 사용자가 프래그먼트를 떠난다는 첫 번째 신호이다. 현재 사용자가 세션을 넘어서 지속되어야 하는 변경 사항을 적용하려면 이곳에서 해야 한다.
onStop()
: 프래그먼트는 더 이상 보여지지 않게되며 기능을 할 수 없다.
onSaveInstanceState()
: onStop() 함수 다음에 호출되므로 이 함수가 호출된다는 것은 액티비티가 종료됐다는 것을 의미한다.
onDestoryView()
: 프래그먼트에 View들을 제거한다. 만약 add 할 때 backstack을 사용했다면 다시 해당 프래그먼트로 돌아 올 때 onCreateView()가 호출된다.
onDestroy()
: 프래그먼트를 제거하기 직전에 호출된다.
출처 : https://junghun0.github.io/2019/06/08/android-fragment/
https://jminie.tistory.com/164#3.5.%20onViewStateRestored()
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
.
.
.
setDataAtFragment(Fragment1(), "버킷 리스트")
}
//프래그먼트에 데이터(title에 값) 전달하기
fun setDataAtFragment(fragment:Fragment, title:String) {
val bundle = Bundle()
bundle.putString("title", title)
fragment.arguments = bundle
setFragment(fragment)
}
//프래그먼트 띄우기
fun setFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.frameLayout, fragment)
transaction.commit()
setDataAtFragment() 함수는 전달할 데이터를 프래그먼트의 arguments에 넣어주는 함수다.
이 argument는 bundle 객체로 데이터를 전달할 수 있고 bundle 객체는 데이터를 key와 value의 쌍으로 전달합니다.
다음은 MainActivity에서 전달한 데이터를 프래그먼트에서 받는 코드값 입니다.
class Fragment1 : Fragment() {
private var title: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
title = it.getString("title")
}
이렇게 가져올 수 있습니다.
class Fragment1 : Fragment() {
.
.
.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
.
.
.
//'상세보기' 버튼을 눌렀을 때
btnGoDetail.setOnClickListener {
val mActivity = activity as MainActivity
mActivity.receiveData("프래그먼트")
액티비티 객체를 만들어 액티비티에 만들어 둔 함수를 호출해주면 된다. 호출하기 전에 액티비티에는 다음과 같이 receiveData()라는 함수를 만들어놔야 한다.
class MainActivity() {
fun onCreate() {
.
.
.
}
fun receiveData(who:String) {
}
}
class Fragment1 : Fragment() {
.
.
.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
.
.
.
//"상세보기" 버튼을 눌렀을 때
btnGoDetail.setOnClickListener {
val mActivity = activity as MainActivity
mActivity.setDataAtFragment(Fragment2(), "버킷리스트")
}
}
}
MainActivity는 그대로 두고 Fragment2의 onCreate()에서 값을 가져올 수 있다.
class Fragment2 : Fragment() {
private var title: String? = null
override fun onCreated(view: View, savedInstanceState: Bundle?) {
super.onCreated(savedInstanceState)
arguments?.let {
title = it.getString("title")
}
}
}
이렇게 마지막 getString을 통해 데이터를 수신할 수 있다.