<aside> 💡 UI 처리를 위한 메인 스레드

</aside>

애플리케이션은 성능을 위해 멀티 스레드를 많이 활용하지만, UI를 업데이트하는 데는 단일 스레드 모델이 적용된다. 멀티 스레드로 UI를 업데이트하면 동일한 UI 자원을 사용할 때 교착 상태(deadlock), 경합 상태(race condition) 등 여러 문제가 발생할 수 있다. 따라서 UI 업데이트를 메인 스레드에서만 허용한다.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/6639993b-3b70-451d-a7de-bef3e3094670/_2021-02-01__10.57.17.png

경쟁상태 (https://ko.wikipedia.org/wiki/경쟁_상태)

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a1b98987-3d96-40c0-b0df-2cd0c2cdebd1/_2021-02-01__11.00.46.png

교착상태 (https://ko.wikipedia.org/wiki/교착_상태)

앱 프로세스가 시작되면서 메인 스레드가 생성된다. 컴포넌트의 생명주기 메서드와 그 안의 메서드 호출은 기본적으로 메인 스레드에서 실행된다. 메인 스레드는 UI를 변경할 수 있는 유일한 스레드이기 때문에 메인 스레드를 UI 스레드로 부르기도 한다. 서비스, 브로드캐스트 리시버, Application은 사용자 인터페이스가 아니기 때문에, UI 스레드에서 실행된다고 하면 개념을 혼동하기 쉽다. UI를 변경하는 유일한 수단이라는 의미를 강조하기 위해서 UI 스레드를 쓴다고 이해하면 편할 것 같다.

안드로이드 프레임워크 내부 클래스인 android.app.ActivityThread가 애플리케이션의 메인 클래스이고, ActivityThread의 main() 메서드가 애플리케이션의 시작 지점이다. ActivityThread는 어떤 것도 상속하지 않은 클래스다. 액티비티만 관련되어 있는 것도 아니고 모든 컴포넌트들이 다 관련되어 있다.

AppCompatActivity → FragmentActivity → ComponentActivity → androidx.core.app.ComponentActivity → Activity → ActivityThread 로 들어가면 볼 수 있다.

ActivityThread.java

public static void main(String[] args) {
    /* ..*/
    Looper.prepareMainLooper();  // 1번
		/* .. */
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
  
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
		/* .. */   
		Looper.loop(); // 2번

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

1번 → 메인 Looper를 준비한다.

2번 → UI Message를 처리한다. Looper.loop() 메서드에서 무한 반복문이 있기 때문에 main() 메서드는 프로세스가 종료될 때까지 끝나지 않는다.

<aside> 💡 Looper 클래스

</aside>