Context

Context가 없으면 액티비티를 시작할 수도, 브로드캐스트를 발생시킬 수도, 서비스를 시작할 수도 없다. 리소스에 접근할 떄도 Context를 통해서만 가능하다. Context는 여러 컴포넌트의 상위 클래스이다.

Context는 추상 클래스인데 메서드 구현이 거의 없고 상수 정의와 추상 메서드로 이루어진다. Context를 직접 상속한 것은 ContextWrapper이고 ContextWrapper를 상속한 것은

Activity, Service, Application이다. (BroadCastReceiver와 ContentProvider는 Context를 상속한 것이 아님)

ContextWrapper 클래스

ContextWrapper 클래스는 Context를 래핑한 ContextWrapper(Context base) 생성자를 갖고 있다.

public ContextWrapper(Context base) { // 1
    mBase = base;
}

protected void attachBaseContext(Context base) { // 2
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }
    mBase = base;
}

public Context getBaseContext() {
    return mBase;
}

@Override
public Context getApplicationContext() {
    return mBase.getApplicationContext();
}

@Override
public void startActivity(Intent intent) {
    mBase.startActivity(intent);
}

@Override
public void sendBroadcast(Intent intent) {
    mBase.sendBroadcast(intent);
}

@Override
public Resources getResources() {
    return mBase.getResources();
}

1, 2 에서 base 파라미터에 전달되는 것은 Context의 여러 메서드를 직접 구현한 ContextImpl 인스턴스이다.

ContextWrapper의 여러 메서드는 base의 메서드를 그대로 다시 호출한다. Activity, Service, Application은 1의 생성자를 사용하지 않고, 실제로는 2의 attachBaseContext() 메서드를 사용한다.

Activity, Service, Application 모두 내부적으로 ActivityThread에서 컴포넌트가 시작된다. 이떄 각 컴포넌트의 attach() 메서드를 실행하고 attach() 메서드에서 또다시 attachBaseContext() 메서드를 호출한다.

ContextWrapper에 getBaseContext()와 getApplicationContext()라는 2개의 메서드가 별도인 것을 보면 싱글톤이 아닌 것을 알 수 있다.

Activity, Service, Application 컴포넌트는 각각 생성한 ContextImpl을 하나씩 래핑하고 있고 getBaseContext()는 각각 ContextImpl 인스턴스를 리턴한다.

getApplicationContext()는 Application 인스턴스를 리턴하는 것으로 Application은 앱에서 1개밖에 없고 어디서나 동일한 인스턴스를 반환한다.

ContextImpl의 메서드