Android Context

don9wan·2021년 10월 14일
0

Android

목록 보기
12/18
post-thumbnail

오늘은 Android Context에 대해 알아보겠다. Android 개발을 접할 때 간혹 보이던 녀석이다. 이 녀석을 통해 어떠한 문제를 해결한 경험도 있고, 음.. 상당히 추상적인 녀석이 아닐까 싶다. 디벨로퍼 문서로 이동해보자.

시작부터 헷갈리게 하네

  • Context는 Object 클래스를 상속한 클래스(객체)이다.
    • 거의 최상위 클래스임을 알 수 있다.
  • android.content 패키지에 있다.
  • 직속 서브 클래스는 ContextWrapper, MockContext가 있다.
  • 알려진 서브 클래스들이 있는데, 가장 눈에 띄는 것은 단연 Activity이다.

설명

  • 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.

Hey, Papago

  • 애플리케이션 환경에 대한 글로벌 정보에 대한 인터페이스입니다.
  • 안드로이드 시스템에 의해 구현되는 추상 클래스입니다.
  • 이것은 launching activities, broadcasting, receiving intents 등과 같은 애플리케이션 수준 운영을 위한 업콜 뿐만 아니라 애플리케이션별 리소스 및 클래스에 대한 액세스를 가능케합니다.

너무 주옥같은 설명로 가득해서 한줄한줄 번역까지 해봤다. 컨텍스트는 애플리케이션 환경에 대한 글로벌 정보에 대한 인터페이스 역할을 하고, 안드로이드 시스템에 의해 구현되는 추상 클래스라고 한다.

근데 말이다. 어떻게 Context 객체는 애플리케이션 환경에 대한 글로벌 정보를 알 수 있을까? 또, 이상하리만큼 최상위 클래스라는 것을 알 수 있었다. 왜? 왜 너는 그럴 수 있는 것이냐. 좀 더 알아보자.

A few moments later..
구글을 떠돌다 왔습니다.

Level 1. Context

Context란

애플리케이션 환경에 대한 글로벌 정보에 대한 인터페이스 역할을 하고, "안드로이드 시스템에 의해 구현되는 추상 클래스"

Context는

  1. 애플리케이션의 현재 상태를 나타낸다.
  2. 시스템이 관리하고 있는 애플리케이션 정보에 접근한다.
    • getPackageName(), getResource() 등의 메서드
    • 리소스, 데이터베이스, shared preference 등에 접근하기 위해 사용할 수 있다.
  3. 안드로이드 시스템이 제공하는 서비스에 API를 호출하여 사용할 수 있다.
    • startActivity(), bindService() 등의 메서드
  4. ActivityManagerService라는 일종의 애플리케이션에 접근하는 통로 역할

Context의 종류


1. Application Context
2. Activity Context

Application Context
1. 싱글턴 인스턴스(인스턴스가 오직 1개만 생성돼야 하는 객체)이다.

  • 따라서 애플리케이션이 살아있는 동안은 변경되지 않는다.
  1. 액티비티에서 getApplicationContext(), getApplication()를 통해 접근 가능하다.

  2. Application Life-Cycle에 묶여있다.

    • 현재 Context가 종료된 이후에도 Context가 필요한 작업(현재 액티비티 스코프를 벗어난 Context가 필요한 작업)에 적합하다.
    • 애플리케이션에서 생성한 싱글턴 오브젝트(DB 인스턴스 등)가 Context를 필요로 한다면 Application Context를 전달하면 된다.
    • 이 때 Activity Context를 전달하면 해당(DB) 오브젝트가 액티비티를 항상 참조하므로, 액티비티가 화면에 표시되지 않는 순간(pause state 등)에도 가비지 콜렉션이 진행되지 않아 메모리 누수가 발생한다. (클래스가 인자를 참조한다. -> SingleToneObject(baseContext))
  3. 따라서 애플리케이션 전체에서 사용할 라이브러리를 특정 액티비티에서 초기화한다면 당연히 Application Context를 전달해야 한다.

  4. 정리 : 애플리케이션 자체와 연동되는 것이므로, 애플리케이션의 life cycle이 지속되는 동안 동일한 객체다. 즉, 애플리케이션을 종료 후 다시 실행시킬때에만 바뀐다.

Activity Context
1. Application Context와 달리 activity 내에서 유효한 Context이다.
2. this, getBaseContext()를 통해 접근 가능하다.

  1. Activity Life-Cycle에 묶여있다.
    • Context가 Activity와 함께 소멸해야 하는 경우에 사용한다.
    • Toast, Dialog 등 UI operation에서 컨텍스트가 필요하다면 Activity Context를 사용하는 것이 적합하다.
    • 특히 GUI와 관련된 Context 조작은 Application Context보다 Activity Context의 영역이라 보면 된다.
    • startActivity()도 Activity Context 활용의 예이다. Context에 Intent를 통해 새로 띄워진 액티비티는 이전 액티비티와 연관된 상태로 액티비티 스택에 보관되기 때문이다.
  2. 따라서 액티비티와 라이프사이클이 같은 오브젝트를 Context를 필요로 한다면 Activity Context를 전달하면 된다.
  3. 정리 : 액티비티와 연동된 것이므로, 액티비티의 life cycle이 지속되는 동안 동일한 객체다. 액티비티를 파괴시키고 다시 시작시키면 activity context도 바뀐다.

작업 및 오브젝트가 Activity/Application 중 누구의 Life-Cycle을 따라가는 것이 적절한지 파악한 후 Context를 고르면 되는 것 같다.

Level 2. Context

Context의 위치

  • Context 클래스는 Object 클래스를 상속하고 있는 최상단의 클래스이다.
  • Activity, Application, Service, 안드로이드 플랫폼의 주요 클래스들은 모두 Context 클래스의 서브 클래스이다.
  • 따라서 Activity를 포함한 안드로이드의 주요 클래스에서 애플리케이션의 특정자원, 클래스, 환경 정보에 대해 접근할 수 있게 되고,
  • 결과적으로 Context를 이용하면 getPackageName(), getResource(), startActivity(), startService(), getSystemService()와 같이 시스템 레벨의 정보를 얻을수 있는 메소드를 사용할 수 있다. (핵심)
  • 시스템에 대한 리소스 확인, 데이터베이스 및 환경 설정에 대한 액세스 확보 등과 같은 서비스 또한 제공한다.
  • Context 얻기
    • View.getContext(), getBaseContext() : ActivityContext
    • Activity.getApplicationContext() : ApplicationContext
    • ContextWrapper.getBaseContext() : 다른 Context로부터 어떤 Context에 접근해야 하는 경우 ContextWrapper 클래스 사용. 클래스 내부에서 참조되는 Context는 getBaseContext()를 통해 액세스
  • 다른 플랫폼에서는 직접 System API를 호출한다. 하지만 안드로이드는
    • Context를 통해 시스템 API를 호출해 사용한다.
    • 일반적인 플랫폼에선 애플리케이션이 프로세스와 긴밀하게 연결되어 있기 때문이다.
    • 하지만 안드로이드 플랫폼의 애플리케이션은 프로세스와 독립적으로 존재한다. 예를 들자면, 안드로이드 플랫폼에서 프로세스가 없는 상황에도 어플리케이션은 살아있는 것처럼 사용자에게 표시되기도 하고, 메모리가 부족한 상황이 될 경우, 작동중이던 프로세스가 강제로 종료되고 대신 해당 프로세스에서 작동중이던 어플리케이션 관한 일부 정보만 별도로 관리하고, 이 후에 메모리 공간이 확보되면 저장되어있던 어플리케이션 정보를 바탕으로 새로운 프로세스를 시작하는 일이 벌어진다.
    • 안드로이드에서도 프로세스는 당연히 OS 커널에서 관리된다. 어플리케이션과 프로세스가 별도로 관리되고 있다면, 어플리케이션 정보는 어디에서 관리하고 있을지 의문이 든다. 안드로이드의 시스템 서비스 중 하나인 ActivityManagerService에서 그 책임을 진다. 그렇다면 ActivityManagerService는 어떤식으로 어플리케이션을 관리하고 있을까? 특정 토큰을 키 값으로 'key-valule' 쌍으로 이루어진 배열을 이용하여 현재 작동중인 어플리케이션 정보를 관리한다.
    • Context는 어플리케이션과 관련된 정보에 접근하고자 하거나 어플리케이션과 연관된 시스템 레벨의 함수를 호출하고자 할 때 사용된다. 그런데 안드로이드 시스템에서 어플리케이션 정보를 관리하고 있는 것은 시스템이 아닌 ActivityManagerService 라는 일종의 또 다른 어플리케이션이다. 따라서 다른 일반적인 플랫폼과는 달리, 안드로이드에서 어플리케이션과 관련된 정보에 접근하고자 할때는 ActivityManagerService를 통해야만 한다. 당연히 정보를 얻고자 하는 어플리케이션이 어떤 어플리케이션인지에 관한 키 값도 필요하다. 즉, 안드로이드 플랫폼상에서의 관점에서 살펴보면, Context는 두가지 역할을 수행하기 때문에 필요하다.
      • 자신이 어떤 어플리케이션을 나타내고 있는지 알려주는 ID 역할
      • ActivityManagerService 에 접근할 수 있도록 하는 통로 역할

정리 - Android에서 Context를 사용하는 이유

  • 일반 OS 플랫폼에서 어플리케이션은 곧 프로세스이다. 특정 어플리케이션이 OS에게 내가 어떤 프로세스인지 알려주면 어플리케이션 관련된 정보를 얼마든지 획득할 수 있다. 따라서 context와 같은 애매한 중간 매개체가 존재할 이유가 없다.
  • 하지만 안드로이드는 다르다. 특정 어플리케이션이 자신이 본임임을 확인 받을 수 있는 방법은 자신이 작동중인 프로세스를 보여주는 것이 아니라 , 자신이 건내받은 ID카드를 제시하는 것이다. 이 때 ID카드의 역할을 수행하는 것이 바로 context이고, 위변조가 가능하기 때문에 자신의 권한을 제 3의 어플리케이션에게 넘겨주는 PendingIntent와 같은 기능도 가능해진다.
  • Context는 언제 태어날까?
    • 어플리케이션이 태어날 때이다. 그렇다면 하나의 어플리케이션을 구성하는데 각종 컴포넌트 - Activity, Service, BroadcastReceiver 들은 모두 동일한 Context를 공유해서 사용하고 있을까?? 그렇지 않다.
    • Activity 와 Service가 생성될 때 만들어지는 context와 BroadcastReceiver가 호출될 때 전해지는 context는 모두 다른 인스턴스이다. 즉, context는 어플리케이션이 시작될 때는 물론, 컴포넌트들이 생성될때마다 생성된다.
    • 그렇다면 왜 context 인스턴스를 공유하지 않고 모두 서로 다른 인스턴스를 만들어 사용하고 있나?
    • Context 의 기능 중, 시스템 API 를 호출하는 기능과 관련되어 한 가지 문제점이 있다. 어떤 어플리케이션 컴포넌트가 시스템 API를 호출하느냐에 따라서 서로 다른 결과가 나타나야 한다는 점이다. 예를들어, 동일한 형태로 startActivity 메서드 호출하더라도, 일반적인 Activity 에서는 정상적으로 새로운 Activity 를 시작하게 되지만, Service 에서 호출할 경우에는 예외가 발생한다.
    • 만일 어플리케이션을 구성하는 Service 와 Activity 가 서로 동일한 Context 인스턴스를 공유하고 있다면 동일한 메서드 호출에 대하여 서로 다른 결과를 나타내도록 구현하지 못했을 것이다.

더 다양한 context type에 관한 이야기
좀 더 원론적인 Context 이야기
위 블로그의 출처

profile
한 눈에 보기 : https://velog.io/@dongwan999/LIST

0개의 댓글