Android Context의 이해

2020. 7. 2. 23:54

Android Context의 이해

 

안드로이드에서 Context는 항상 필수적으로 사용된다. Activity, Service, Broadcast Receiver 등의 주요 컴포넌트들이 Context와 연결되어 있고 또 이 Context를 이용해서 그것들을 사용할 수 있다.

 

 

Context란 무엇인가?

 

 

Context라는 개념은 Android에서만 사용되는 것이 아니다. 일반적인 프로그래밍에서의 Context는 설정 값에 따라서 바뀔 수 있는 전역 환경 정보, 객체의 상태를 담고 있는 것을 의미한다. 흔히 대학교 운영체제 과목에 나오는 Context Switching의 의미가 크게 다르지 않다. 다른 Process로 전환할 때 Context, 문맥 즉 해당 프로세스의 전역 환경정보(ID, State, Program Counter, Scheduling Information, Memory Information 등과 같은 정보들이 해당)를 다른 Process로 전환하는 것을 의미한다. 이 개념을 바탕으로 Thread, Process, Activity, Application 등 각각의 영역은 다르지만 각 영역에 맞는 환경 정보를 가지고 있고, 이를 전환하여 다른 처리를 하는 것이다.

 

 

 

Android Context

 

Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc

 

  • 어플리케이션 환경에 대한 전역 정보 인터페이스 
  • 시스템에 의해 구현되어 제공되는 추상클래스
  • 어플리케이션 관련 Resource, Class 에 대한 접근 
  • Activity, Broadcasting, Intent 등을 다루기 위한 API 호출

 

Application과 시스템의 전역적인 환경정보를 저장하고 있다는 점에서 위에서 설명한 Context와 비슷하다는 생각할 수 있다. 하지만 다른 부분은 안드로이드에서는 인스턴스화 된 Context를 이용한다. 

 

 

어플리케이션 환경에 대한 전역 정보 인터페이스

 

전역 정보(Global Information)라는 표현이 어디가지를 의미하는 것인지 명확하지 않다. 다만, 현재 실행되고 있는 Application 환경과 관련된 모든 정보들을 의미한다. 실제로 프로세스를 디버깅해보면 Context 정보 - apk, package, resource, database, preference, permission 등 Application과 관련된 환경정보를 가지고 있다.

 

 

시스템에 의해 구현되어 제공되는 추상클래스

 

안드로이드 프레임워크의 Context의 구조를 보면, Context를 ContextWrapper가 상속하고 있다. ContextWrapper는 다시 Application, Activity, Service가 상속하고 있다. 이는 Application을 실행되는 시점부터 Application Context를 사용할 수 있다.

 

Process 내에서 getApplicationContext()를 호출하면 동일한 Application Instance를 통해서 Context를 얻을 수 있다. 하지만, Activity를 통해 얻을 수 있는 Context는 각각의 Component 마다(Activity 혹은 Service) 다른 Instance에서 제공된다. 물론 다른 Instance이기는 하지만 기본적으로 모두 같은 Context를 Base로 생성되며 각 Component의 추가적인 정보, 즉 Activity라면 Activity 관련된 정보가 추가되어 고유한 Context가 되는 것이다.

 

 

어플리케이션 관련 Resource, Class 에 대한 접근 

 

getResource(), getString() 등과 같은 API는 Activity가 상속받고 있는 Context에 정의되어 있는 API이다. 이 API를 통해서 시스템이 관리하고 있는 전역정보들을 가져오고 이를 사용할 수 있게 된다.

 

 

Activity, Broadcasting, Intent 등을 다루기 위한 API 호출

 

 

startActivity(), registerReceiver() 등과 같이 새로운 Component를 생성하기 위한 API들이 제공한다. Android Platform 내에서는 각각의 컴포넌트를 관장하는 별도의 Process(Service)가 존재하며, 이 Process가 어떤 Application Process에서 요청했는지 식별하기 위해 Context를 이용한다. 또한, ActivityManager, PackageManager 등과 같이 시스템 컴포넌트를 사용하기 위한 시작점을 제공한다.

 

 

 

UI Context

 

 

ContextThemeWrapper만이 UI Context이라고해도 무방하고 이는 Context와 Theme를 의미하는 것이다.

 

모든 Activity들은 ContextThemeWrapper를 상속받고 있기 때문에 우리는 원하는 XML을 언제든지 inflate할 수 있다.

Activity는 UI Context로 사용할 수 있고, FragmentManager를 통해 attached된 Fragment는 getContext()를 통해서 UI Context를 얻을 수 있다.

 

하지만, View.getContext()는 UI Context를 개런티하지 않는다. 만약 View가 UI Context와 함께 Layout Inflater를 사용하여 Instance를 만들었다면, UI Context를 얻을 수 있다. 그러나 UI Context를 사용하지 않고 instance화 되었다면 다른 Context를 다시 얻을 수도 있다.

 

final LayoutInflater goodInflater = getInflater((Activity)this); 
final LayoutInflater badInflater = getInflater(getApplicationContext());

 

Non-UI Context

 

쉽게 말해, ContextThemeWrapper를 제외한 Context를 Non-UI Context라고 할 수 있다. UI Context와 거의 모든 작업을 수행할 수 있지만, Theme를 적용할 수 없다.

 

Scenario 1
Lets say you are inflating a layout and you use Non-UI Context. What may go wrong? You can guess in this case: you will not get a themed layout. Not so bad, hmm? It’s bearable.
Scenario 2
You pass UI-Context to someplace where all it needs is resource access or file system access. What can no wrong? Short Answer: Nothing. Remember, UI-Context = Context + Theme. It will gladly serve as context for you.
Scenario 3
You pass UI-Context to someplace where all it needs is resource access or file system access but it is a long operation in the background. Say downloading a file. Now what can go wrong? Short Answer: Memory leak.

 

 

Activity.this

 

Activity.this는 Activity를 상속받은 자신의 클래스를 참조하지만 Activity 또한 Context Class를 상속받았으므로 Activity Context를 제공하는데 사용할 수 있다.

 

 

getApplication()

 

getApplicatoin()은 Application 객체를 참조하지만, Application Class는 Context를 상속받았으므로 Application Context를 제공하는데 사용할 수 있다.

 

 

getApplicationContext()

 

getApplicationContext()는 Application Context를 제공한다.

 

 

getBaseContext()

 

activity context를 제공한다.

 

 

getApplicationContext()와 getBaseContext() 차이점이 크게 와닿지 않는다. 우리는 모바일 기기에는 많은 Factor들이 있다는 것을 알고 있다. 예를 들어, Configuration 항상 변경되고 Locale은 명시적 혹은 암시적으로 변경될 수 있다. 이러한 모든 변경사항은 현재 구성에 가장 적합한 리소스를 선택할 수 있도록 App을 다시 생성하도록 트리거한다. Portrait, Landscape, Tablet, 한국어, 중국어 등 App은 최상의 사용자 경험을 제공하기 위해 그에 걸맞는 가장 적합한 리소스를 필요로하고 이 리소스를 제공하는 것이 Context이다.

 

예를 들어, 사용자 Locale와 달리 UK resource에 접근하려고 한다면?

 

Configuration configuration = getResources().getConfiguration();
configuration.setLocale(your_custom_locale);

context = createConfigurationContext(configuration);

 

우리는 원하는 종류의 Context를 얻을 수 있고 이는 Themed Context를 만들어 원하는 테마로 뷰를 확장하는 데 사용할 수 있다. 이 의미는 Activity Context가 우리가 생각하는 Context가 아니라 Customized context가 제공될 수도 있다.

 

BaseContext는 Delegate Pattern을 통해 Activity의 Context를 반환하게 된다.

 

@Overide
protected void attachBaseContext (Context base) {
	super.attachBaseContext(useYourCustomContext);
}

즉, ApplicationContext는 Application의 life cycle에 맞춰 긴 Non-UI Context이고, BaseContext는 Activity Context를 받을 수 있다.

 

 

Android Platform는 Context + Java Code라고 해도 될 정도로 Context가 Android의 핵심이다. 그리고 이를 알면 알 수록 흥미로운 것들이 있다.

 

 

 

 

 

참고문헌

 

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

http://starryz.tistory.com/4%EF%BB%BF

https://www.freecodecamp.org/news/mastering-android-context-7055c8478a22/

 

https://shnoble.tistory.com/57