Activity, Fragment 와 같은 생명 주기를 가진 컴포넌트들은 특정 상황이 되면 Android 프레임워크에서 자동으로 Lifecycle Callback 메서드를 호출해줍니다. Activity 의 각 Lifecycle Callback 메서드에 Log 를 찍어보면 현재 Lifecycle state 가 어떤 지 금방 확인할 수 있지만, 어떤 경로를 통해 Lifecycle 의 state 가 변경되는 지 코드를 통해 분석해보기로 했습니다.
아래의 Activity Lifecycle state 가 업데이트 되는 경로는 앱을 처음 실행하여 MainActivity 가 실행될 때의 경로를 확인한 것입니다. ActivityThread 에서 관찰중인 Looper 에 새로운 Activity 를 실행해달라는 메시지가 등록되며, Looper 에서 메시지를 꺼내 메시지 종류에 따라 ActivityThread 의 적절한 메서드를 호출함으로써 Activity 생성과 Lifecycle state 업데이트 작업이 트리거 됩니다.
handleLaunchActivity(ActivityThread) → performLaunchActivity(ActivityThread)
→ callActivityOnCreate(Instrumentation)
→ performCreate(Activity) → dispatchActivityPostCreated(Activity)
→ onActivityPostCreated(ReportFragment) → dispatch(ReportFragment)
→ handleLifecycleEvent(LifecycleRegistry)
1. ActivityThread 의 performLaunchActivity() 메서드가 호출되면 매개변수로 전달된 ActivityClientRecord 인스턴스에서 Intent 인스턴스 내의 ComponentName 인스턴스를 통해 Activity 인스턴스를 생성합니다.
Activity 인스턴스를 생성한 후 Instrumentation 인스턴스의 callActivityOnCreate() 메서드를 호출합니다.
(Activity 의 attach() 메서드 내에서 mUiThread 와 mMainThread 필드를 설정합니다.
mUiThread 는 Thread.currentThread() 로 설정하며, mMainThread 는 attach() 메서드의 2번째 매개변수인 ActivityThread 인스턴스입니다. 일반적으로 Main Thread 와 UI Thread 를 동의어로 이해하고 있지만 Activity 내부에서 Main Thread 는 UI 를 업데이트하는 Thread 인스턴스를 지칭하는 것이 아닌 Activity, Service 등 컴포넌트의 인스턴스를 생성하는 등의 작업을 하는 기반 클래스인 ActivityThread 클래스의 인스턴스를 지칭하는 것을 확인할 수 있었습니다.)
public final class ActivityThread {
/**
* 전달된 Intent 내의 Activity ComponentName 을 통해 Activity 인스턴스를 생성하고
* 생성된 Activity 인스턴스에 Window, Theme 등 설정을 한 후
* callActivityOnCreate() 메서드를 호출합니다.
*/
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ComponentName component = r.intent.getComponent();
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
}
if (activity != null) {
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
r.assistToken, r.shareableActivityToken);
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
}
}
}
2. 매개변수로 전달받은 Activity 인스턴스의 performCreate() 메서드를 호출합니다.
icicle 인스턴스는 onCreate 등의 Lifecycle Callback 메서드에 전달되는 savedInstanceState Bundle 입니다.
public class Instrumentation {
/**
* Activity 클래스의 performCreate() 메서드를 호출합니다.
*/
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
}
3. Activity 계층 구조에서 Override 된 onCreate() 메서드를 호출합니다.
MainActivity onCreate() → FragmentActivity onCreate() → ComponentActivity onCreate() → Activity onCreate()
onCreate() 메서드 호출이 끝나면 dispatchActivityPostCreated() 메서드를 호출합니다.
public class Activity extends ContextThemeWrapper
final void performCreate(Bundle icicle) {
performCreate(icicle, null);
}
/**
* Activity 클래스 계층 구조의 Override 된 onCreate() 메서드를 호출합니다.
*/
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
if (persistentState != null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);
}
dispatchActivityPostCreated(icicle);
}
private void dispatchActivityPostCreated(@Nullable Bundle savedInstanceState) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i = 0; i < callbacks.length; i++) {
((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPostCreated(this,
savedInstanceState);
}
}
getApplication().dispatchActivityPostCreated(this, savedInstanceState);
}
}
4. ReportFragment 의 internal class 인 LifecycleCallbacks 의 onActivityPostCreated() 메서드가 호출되면
companion object 에 선언된 dispatch() 메서드를 호출합니다.
dispatch() 메서드 내에서는 ActivityThread 에서 생성한 Activity 인스턴스의 getLifecycle() 메서드를 호출하여 얻은 Lifecycle 인스턴스의 handleLifecycleEvent() 메서드를 호출하여 Activity 의 Lifecycle state 를 업데이트 합니다.
open class ReportFragment() : android.app.Fragment() {
@RequiresApi(29)
internal class LifecycleCallbacks : Application.ActivityLifecycleCallbacks {
override fun onActivityPostCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
dispatch(activity, Lifecycle.Event.ON_CREATE)
}
}
companion object {
/**
* ComponentActivity 클래스가 LifecycleOwner 인터페이스를 구현하였으므로
* ComponentActivity 인스턴스의 getLifecycle() 메서드를 호출하여 얻은 LifecycleRegistry 인스턴스의 handleLifecycleEvent() 메서드를 호출합니다.
*
*/
@JvmStatic
internal fun dispatch(activity: Activity, event: Lifecycle.Event) {
if (activity is LifecycleRegistryOwner) {
activity.lifecycle.handleLifecycleEvent(event)
return
}
if (activity is LifecycleOwner) {
val lifecycle = (activity as LifecycleOwner).lifecycle
if (lifecycle is LifecycleRegistry) {
lifecycle.handleLifecycleEvent(event)
}
}
}
}
}
open class LifecycleRegistry private constructor(
provider: LifecycleOwner,
private val enforceMainThread: Boolean
) : Lifecycle() {
/**
* 해당 메서드가 Main Thread 에서 실행되었는지 확인한 후(해당 메서드는 ActivityThread 의 Main Thread 와 연결된 Main Looper 의 Message 를 통해 실행되었으므로 Main Thread 에서 실행된 메서드입니다.)
* Lifecycle state 를 매개변수로 전달받은 Event 의 state 로 이동시킵니다.
*/
open fun handleLifecycleEvent(event: Event) {
enforceMainThreadIfNeeded("handleLifecycleEvent")
moveToState(event.targetState)
}
/**
* current state 와 새로운 state 가 동일한지 검사하고, current state 가 INITIALIZED 이고 새로운 state 가 DESTROYED 인지 검사합니다.
* current state 를 새로운 state 로 설정한 후 sync() 메서드를 호출합니다.
* current state 가 DESTROYED 인 경우 Lifecycle 에 설정된 observer 인스턴스들이 등록된 observerMap 의 참조를 초기화합니다.
*/
private fun moveToState(next: State) {
if (state == next) {
return
}
check(!(state == State.INITIALIZED && next == State.DESTROYED)) {
"no event down from $state in component ${lifecycleOwner.get()}"
}
state = next
if (handlingEvent || addingObserverCounter != 0) {
newEventOccurred = true
// we will figure out what to do on upper level.
return
}
handlingEvent = true
sync()
handlingEvent = false
if (state == State.DESTROYED) {
observerMap = FastSafeIterableMap()
}
}
/**
* 추가된 observer 들의 state 와 current state 가 동기화될 때 까지 while 문을 수행합니다.
* current state 가 observerMap 에 가장 처음 추가된 observer 의 state 보다 작다면 backwardPass() 메서드를 호출합니다.
* current state 가 observerMap 에 가장 최근 추가된 observer 의 state 보다 크다면 forwardPass() 메서드를 호출합니다.
*/
private fun sync() {
val lifecycleOwner = lifecycleOwner.get()
?: throw IllegalStateException(
"LifecycleOwner of this LifecycleRegistry is already " +
"garbage collected. It is too late to change lifecycle state."
)
while (!isSynced) {
newEventOccurred = false
if (state < observerMap.eldest()!!.value.state) {
backwardPass(lifecycleOwner)
}
val newest = observerMap.newest()
if (!newEventOccurred && newest != null && state > newest.value.state) {
forwardPass(lifecycleOwner)
}
}
newEventOccurred = false
}
/**
* 가장 마지막에 처음 추가된 observer 와 가장 마지막에 추가된 observer 가 소유한 state 가 동일하며,
* current state 가 가장 최근에 추가된 observer 가 소유한 state 와 동일하면 state 가 동기화 되어있다고 판단합니다.
*/
private val isSynced: Boolean
get() {
if (observerMap.size() == 0) {
return true
}
val eldestObserverState = observerMap.eldest()!!.value.state
val newestObserverState = observerMap.newest()!!.value.state
return eldestObserverState == newestObserverState && state == newestObserverState
}
}
'android > Android 코드' 카테고리의 다른 글
setContentView (1) | 2023.12.26 |
---|