일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 서비스 vs 쓰레드
- 안드로이드 유닛테스트란
- 안드로이드 레트로핏 사용법
- android retrofit login
- 멤버변수
- jvm 작동 원리
- ANR이란
- 자바 다형성
- 스택 자바 코드
- rxjava disposable
- 안드로이드 라이선스
- 큐 자바 코드
- rxjava hot observable
- 객체
- 안드로이드 레트로핏 crud
- 안드로이드 라이선스 종류
- rxjava cold observable
- 플러터 설치 2022
- Rxjava Observable
- android ar 개발
- 안드로이드 os 구조
- 스택 큐 차이
- 클래스
- jvm이란
- 안드로이드 유닛 테스트
- ar vr 차이
- 2022 플러터 안드로이드 스튜디오
- 서비스 쓰레드 차이
- 안드로이드 유닛 테스트 예시
- 2022 플러터 설치
- Today
- Total
나만을 위한 블로그
[Android] Context, ContextImpl, ContextWrapper란? 본문
안드로이드의 Context는 추상 클래스로, 리소스 접근이나 액티비티 등 안드로이드 컴포넌트를 실행할 때 필요하다. 공식문서를 확인해보자.
https://developer.android.com/reference/kotlin/android/content/Context
앱 환경에 대한 전역 정보 인터페이스다. 안드로이드 시스템에서 구현을 제공하는 추상 클래스다. 앱 리소스, 클래스에 대한 접근은 물론 launch activity, 브로드캐스팅, 인텐트 수신 등 앱 수준 작업에 대한 상향 호출을 허용한다
액티비티를 이동할 때 startActivity()를 호출하는데 이 함수의 1번 인자로 Context를 넘기며, 다이얼로그를 사용할 때 배경색을 dim 처리할 때도 사용하는 등 Context는 무궁무진한 곳에 사용된다.
그러나 Context의 본질은 추상 클래스기 때문에, 어딘가에서 이걸 상속받아 구현해야 Context 안의 함수들을 사용할 수 있을 것이다. 이 때 Context를 상속받은 클래스가 ContextWrapper다.
https://developer.android.com/reference/android/content/ContextWrapper
모든 호출을 다른 Context에 위임하는 Context의 프록시 구현이다. 원래 컨텍스트를 바꾸지 않고 동작을 수정하기 위해 서브클래싱할 수 있다
그리고 ContextImpl이란 것도 존재하는데 ContextImpl 또한 Context를 상속받은 클래스다.
ContextImpl과 ContextWrapper의 차이는 Context의 기본 구현체가 ContextImpl이고, 이것은 개발자에게 노출되지 않고 ContextWrapper 안에 감싸여진 형태로 존재한다. ContextImpl은 안드로이드 스튜디오에서도 소스코드를 확인할 수 없어 별도의 링크에서 확인해야 한다. 아래 링크로 들어가서 ContextImpl을 검색하면 볼 수 있다.
글로만 Context, ContextWrapper, ContextImpl이 작동하는 걸 위에 적었는데 잘 이해가 안 된다. 인터넷을 돌면서 클래스 다이어그램 형태로 표시한 그림들이 있어 참고를 위해 가져왔다. 두 이미지를 같이 보면 어떤 식으로 작동하는지 이해될 것이다.
아래는 다른 사이트에서 설명하는 내용이다. 안드로이드 디벨로퍼의 내용이 일부 포함돼 있다.
https://ericyang505.github.io/android/Context.html
안드로이드 앱은 자바를 사용하지만 자바와 달리 클래스와 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
Context와 ContextWrapper의 차이점은 아래의 다양한 메서드의 리턴값을 보면 이해할 수 있다
View.getContext() : 뷰가 현재 실행 중인 컨텍스트를 반환한다. 일반적으로 현재 활성된 액티비티다
Activity.getApplicationContext() : 전체 앱(모든 액티비티가 내부에서 실행되는 프로세스)에 대한 컨텍스트를 반환한다. 현재 액티비티 뿐 아니라 전체 앱의 생명주기에 연결된 컨텍스트가 필요한 경우, 현재 액티비티의 컨텍스트 대신 이걸 써라
ContextWrapper.getBaseContext() : 다른 컨텍스트 안에서 컨텍스트에 접근해야 하는 경우 ContextWrapper를 사용한다. 해당 ContextWrapper 내부에서 참조되는 Context는 getBaseContext()를 통해 접근된다
this : 뷰의 컨텍스트를 반환한다(먼저 뷰를 참조하지 않는 경우 뷰에 대해 알고 있기를 바란다). 일반적으로 현재 활성된 액티비티다
https://www.geeksforgeeks.org/what-is-context-in-android/
(중략)...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;
}
}
일부 동작을 재정의할 수 있다. 예를 들어 앱의 기본 컨텍스트를 가진 다음 ContextWrapper에 넣고 리소스 객체를 재정의해서 테마를 지정한다(안드로이드가 실제로 수행하는 작업). 하위 클래스가 아닌 이 작업을 수행하는 이유는 매우 무거운 객체 2개를 만들지 않아도 되기 때문이다. 둘 사이에 변수를 공유할 수도 있지만 메모리 누수 가능성이 높아진다. 객체 생성 비용이 많이 들 수 있지만 이미 수행된 경우 프록시를 써서 이를 방지할 수 있다
https://stackoverflow.com/questions/66308445/what-is-contextwrapper-in-android
(중략)...ContextWrapper를 확장하는 다른 클래스를 작성하면 해당 클래스가 대리자 컨텍스트(delegate context)의 일부 메서드를 재정의할 수 있다. 예를 들어 getAssets 또는 getResources다. 대부분의 앱은 그렇게 할 필요가 없지만 일부 더 정교한 응용 프로그램의 경우 이는 매우 강력한 기능이다
확인한 내용들을 정리하면, ContextImpl은 Context를 상속받아서 구현한 클래스고, ContextWrapper는 Context를 통해 사용할 수 있는 getResources() 등의 함수들을 재정의할 수 있으며 ContextImpl을 사용해 Context의 함수에 접근할 수 있다. 이 때 Context의 메서드를 재정의해서 사용할 수 있다. 재정의해서 사용하더라도 디벨로퍼의 설명대로, 원래 Context가 바뀌는 일 없이 내가 원하는 대로 작동 방식을 수정할 수 있다.
사용할 일이 얼마나 있을까 싶은 클래스지만 알아서 나쁜 개발 지식은 없으니 이런 게 있구나 하고 넘어간다.
'Android' 카테고리의 다른 글
[Android] 단위 테스트 실행 시 No tests found for given includes 에러 해결 (0) | 2023.03.15 |
---|---|
[Android] StateFlow vs SharedFlow (0) | 2023.03.14 |
[Android] Android 13 변경사항 (0) | 2023.02.27 |
[Android] 안드로이드 스튜디오 Electric Eel 업데이트 후 앱 실행 시마다 Run 탭 올라오지 않게 하기 (0) | 2023.02.04 |
[Android] Coroutine의 Job과 Dispatchers란? (0) | 2023.01.31 |