관리 메뉴

나만을 위한 블로그

[Android] Context, ContextImpl, ContextWrapper란? 본문

Android

[Android] Context, ContextImpl, ContextWrapper란?

참깨빵위에참깨빵_ 2023. 3. 1. 00:36
728x90
반응형

안드로이드의 Context는 추상 클래스로, 리소스 접근이나 액티비티 등 안드로이드 컴포넌트를 실행할 때 필요하다. 공식문서를 확인해보자.

 

https://developer.android.com/reference/kotlin/android/content/Context

 

Context  |  Android Developers

 

developer.android.com

앱 환경에 대한 전역 정보 인터페이스다. 안드로이드 시스템에서 구현을 제공하는 추상 클래스다. 앱 리소스, 클래스에 대한 접근은 물론 launch activity, 브로드캐스팅, 인텐트 수신 등 앱 수준 작업에 대한 상향 호출을 허용한다

 

액티비티를 이동할 때 startActivity()를 호출하는데 이 함수의 1번 인자로 Context를 넘기며, 다이얼로그를 사용할 때 배경색을 dim 처리할 때도 사용하는 등 Context는 무궁무진한 곳에 사용된다.

그러나 Context의 본질은 추상 클래스기 때문에, 어딘가에서 이걸 상속받아 구현해야 Context 안의 함수들을 사용할 수 있을 것이다. 이 때 Context를 상속받은 클래스가 ContextWrapper다.

 

https://developer.android.com/reference/android/content/ContextWrapper

 

ContextWrapper  |  Android Developers

 

developer.android.com

모든 호출을 다른 Context에 위임하는 Context의 프록시 구현이다. 원래 컨텍스트를 바꾸지 않고 동작을 수정하기 위해 서브클래싱할 수 있다

 

그리고 ContextImpl이란 것도 존재하는데 ContextImpl 또한 Context를 상속받은 클래스다.

ContextImpl과 ContextWrapper의 차이는 Context의 기본 구현체가 ContextImpl이고, 이것은 개발자에게 노출되지 않고 ContextWrapper 안에 감싸여진 형태로 존재한다. ContextImpl은 안드로이드 스튜디오에서도 소스코드를 확인할 수 없어 별도의 링크에서 확인해야 한다. 아래 링크로 들어가서 ContextImpl을 검색하면 볼 수 있다.

 

https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/ContextImpl.java 

 

core/java/android/app/ContextImpl.java - platform/frameworks/base - Git at Google

 

android.googlesource.com

 

글로만 Context, ContextWrapper, ContextImpl이 작동하는 걸 위에 적었는데 잘 이해가 안 된다. 인터넷을 돌면서 클래스 다이어그램 형태로 표시한 그림들이 있어 참고를 위해 가져왔다. 두 이미지를 같이 보면 어떤 식으로 작동하는지 이해될 것이다.

 

 

https://black-jin0427.tistory.com/220
https://s2choco.tistory.com/10

 

아래는 다른 사이트에서 설명하는 내용이다. 안드로이드 디벨로퍼의 내용이 일부 포함돼 있다.

 

https://ericyang505.github.io/android/Context.html

 

https://ericyang505.github.io/android/Context.html

Fully understand Context in Android Can we do Activity mActivity = new Activity()? Android application is using java, but not like java that you can create a class and main() function, then able to run. Android is based on components including Activity, Se

ericyang505.github.io

안드로이드 앱은 자바를 사용하지만 자바와 달리 클래스와 main()을 생성한 다음 실행할 수 있다. 안드로이드는 액티비티, 서비스, 컨텐츠 프로바이더, 브로드캐스트 리시버를 포함한 컴포넌트를 기반으로 한다. 이런 모든 컴포넌트에는 자체 컨텍스트가 있으므로 단순히 new를 써서 새 컴포넌트를 만들 수 없다. 액티비티는 컨텍스트에서 확장되고 서비스, Application도 컨텍스트에서 확장된다. 앱 환경에 대한 전역 정보에 대한 인터페이스다. 안드로이드 시스템에서 구현을 제공하는 추상 클래스다. 앱 별 리소스 및 클래스에 대한 접근은 물론 launching activity, 브로드캐스팅 및 인텐트 수신 같은 앱 수준 작업에 대한 상향 호출을 허용한다.

소스코드에서 이전(previous) 클래스 다이어그램을 얻을 수 있다. ContextImpl은 모든 컨텍스트 추상 함수를 구현하고 ContextWrapper는 Context에서 ContextImpl 클래스 구현을 사용해 모든 함수를 래핑한다
attachBaseContext()는 ContextWrapper 클래스가 컨텍스트가 한 번만 연결되게 한다. ContextThemeWrapper는 이름처럼 매니페스트에서 "android:theme"로 정의된 액티비티 또는 Application에서 테마를 적용한다. Application과 서비스 모두 테마가 필요하지 않으므로 ContextWrapper에서 직접 상속된다. 활동 중에 앱과 서비스가 시작되고 Context에서 기능을 구현하는 새 ContextImpl 객체가 매번 생성된다
public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    
    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     * 
     * @param base The new base context for this wrapper.
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    ......
}

 

그럼 이 구조는 왜 만들어지게 된 것인가?

 

https://www.quora.com/What-is-meant-by-Context-in-Android-in-simple-words-and-ContextWrapper

 

What is meant by Context in Android (in simple words) and ContextWrapper?

Answer: Pradhan Rishi Sharma's answer to What is a context in Java? Just to give you an analogy in non-programming terms, think of it this way : you are having a dream and you wake from it by a hypnic jerk. The immediate change of environment for your brai

www.quora.com

Context와 ContextWrapper의 차이점은 아래의 다양한 메서드의 리턴값을 보면 이해할 수 있다

View.getContext() : 뷰가 현재 실행 중인 컨텍스트를 반환한다. 일반적으로 현재 활성된 액티비티다
Activity.getApplicationContext() : 전체 앱(모든 액티비티가 내부에서 실행되는 프로세스)에 대한 컨텍스트를 반환한다. 현재 액티비티 뿐 아니라 전체 앱의 생명주기에 연결된 컨텍스트가 필요한 경우, 현재 액티비티의 컨텍스트 대신 이걸 써라
ContextWrapper.getBaseContext() : 다른 컨텍스트 안에서 컨텍스트에 접근해야 하는 경우 ContextWrapper를 사용한다. 해당 ContextWrapper 내부에서 참조되는 Context는 getBaseContext()를 통해 접근된다
this : 뷰의 컨텍스트를 반환한다(먼저 뷰를 참조하지 않는 경우 뷰에 대해 알고 있기를 바란다). 일반적으로 현재 활성된 액티비티다

 

https://www.geeksforgeeks.org/what-is-context-in-android/

 

What is Context in Android? - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

(중략)...ContextWrapper 사용의 이점은 원래 Context를 변경하지 않고 동작을 수정할 수 있다는 것이다
public <YourHandler>(Context ctx) {
    // if the context is instanceof ContextWrapper
    while (ctx instanceof ContextWrapper) {
        // use getBaseContext()
        final Context baseContext = ((ContextWrapper)context).getBaseContext();
        if (baseContext == null) {
            break;
        }
        // And then we can assign to context and reuse that
        ctx = baseContext;
    }
}

 

https://stackoverflow.com/questions/55318150/what-is-the-purpose-of-contextwrapper-having-a-proxy-for-context

 

What is the purpose of ContextWrapper (having a proxy for Context)?

According to the Android documentation, ContextWrapper is a "[p]roxying implementation of Context that simply delegates all of its calls to another Context. Can be subclassed to modify behavior wit...

stackoverflow.com

일부 동작을 재정의할 수 있다. 예를 들어 앱의 기본 컨텍스트를 가진 다음 ContextWrapper에 넣고 리소스 객체를 재정의해서 테마를 지정한다(안드로이드가 실제로 수행하는 작업). 하위 클래스가 아닌 이 작업을 수행하는 이유는 매우 무거운 객체 2개를 만들지 않아도 되기 때문이다. 둘 사이에 변수를 공유할 수도 있지만 메모리 누수 가능성이 높아진다. 객체 생성 비용이 많이 들 수 있지만 이미 수행된 경우 프록시를 써서 이를 방지할 수 있다

 

https://stackoverflow.com/questions/66308445/what-is-contextwrapper-in-android

 

What is ContextWrapper in Android?

This is what the documentation for ContextWrapper states: Proxying implementation of Context that simply delegates all of its calls to another Context. Can be subclassed to modify behavior without

stackoverflow.com

(중략)...ContextWrapper를 확장하는 다른 클래스를 작성하면 해당 클래스가 대리자 컨텍스트(delegate context)의 일부 메서드를 재정의할 수 있다. 예를 들어 getAssets 또는 getResources다. 대부분의 앱은 그렇게 할 필요가 없지만 일부 더 정교한 응용 프로그램의 경우 이는 매우 강력한 기능이다

 

확인한 내용들을 정리하면, ContextImpl은 Context를 상속받아서 구현한 클래스고, ContextWrapper는 Context를 통해 사용할 수 있는 getResources() 등의 함수들을 재정의할 수 있으며 ContextImpl을 사용해 Context의 함수에 접근할 수 있다. 이 때 Context의 메서드를 재정의해서 사용할 수 있다. 재정의해서 사용하더라도 디벨로퍼의 설명대로, 원래 Context가 바뀌는 일 없이 내가 원하는 대로 작동 방식을 수정할 수 있다.

사용할 일이 얼마나 있을까 싶은 클래스지만 알아서 나쁜 개발 지식은 없으니 이런 게 있구나 하고 넘어간다.

반응형
Comments