컨텍스트(Context)란?
컨텍스트란 작게는 어플리케이션 자신이 가지고 있는 이미지, 문자열, 레이아웃 같은 리소스 참조를, 크게는 안드로이드 시스템 서비스에 접속하기 위한 관문 역할을 하는 객체다.
이에 대해서는 이미 좋은 글이 있다.
컨텍스트(Context)를 얻는 방법에는 무엇이 있나?
- 액티비티나 서비스에서 getApplicationContext() 호출 :
Application 객체가 Context 형으로 반환된다. - 액티비티나 서비스에서 getApplication() 호출 :
Application 객체가 반환되지만, Context 형 변수에 담아 Context로 쓸 수 있다. - 액티비티, 서비스, 컨텐츠 프로바이더에서 getContext() 호출 :
컨텍스트 객체가 반환된다. 참고로, 컨텐츠 프로바이더에서는 생성자를 통해 미리 저장해둔 컨텍스트 객체를 반환하는 것이다. - BroadcastReceiver의 onReceive(…) 함수의 파라미터로 전달 :
onReceive()가 호출 될 때마다 새로 만든 컨텍스트 객체가 전달된다. 참고로, 이 컨텍스트 객체를 통해서는 bindService()나 registerReceiver()를 호출할 수 없다. - View에서 getContext() 호출 :
모든 뷰는 자신이 표시되는 액티비티 컨텍스트의 참조를 가지고 있다. 이를 반환한다.
컨텍스트(Context)? 액티비티 컨텍스트(context-activity)? 어플리케이션 컨텍스트(context-application)?
컨텍스트를 수명에 따라 컴포넌트(보통은 액티비티)의 컨텍스트(context-activity)와 어플리케이션 컨텍스트(context-application) 두 가지로 구분해보자. 액티비티나 서비스의 컨텍스트가 컴포넌트의 컨텍스트, 프로세스의 컨텍스트가 어플리케이션 컨텍스트다.
어플리케이션 컨텍스트는 프로세스의 라이프 사이클을 따르기 때문에 앱이 죽기 전까지 singletone instance로 동일한 객체를 반환하지만, 액티비티 컨텍스트는 액티비티의 라이프 사이클에 따라 쉽게 사라지고 다시 만들 수 있다. 단말을 가로/세로로 돌리는 경우처럼 말이다.
getContext(), getBaseContext(), getApplicationContext(), getApplication(), Activity.this/Service.this의 차이는 무엇인가?
액티비티나 서비스의 this는 getContext()와 같은 객체를 가리킨다. 액티비티와 서비스는 Context 클래스(정확히는 ContextWrapper)를 상속받은 클래스이기 때문이다. 참고로, 컨텐츠 프로바이더와 브로드캐스트 리시버는 Context 클래스의 하위 클래스가 아니므로, this 변수를 컨텍스트로 쓸 수 없다.
Activity.getApplication()과 Context.getApplicationContext()는 Application 객체를 반환한다. 다만, getApplication()은 Application 형으로 getApplicationContext()은 Context 형으로 반환한다.
보통, 컨텍스트는 액티비티 안에서 많이 사용하므로, 어플리케이션 컨텍스트(context-application)와 액티비티 컨텍스트(context-activity)라고 불러 구분하기도 한다.
그럼 컨텐츠 프로바이더와 브로드캐스트 리시버는 컨텍스트(Context)를 어디서 구하나?
컨텐츠 프로바이더는 getContext() 메소드를 제공한다. 단, onCreate()가 호출된 후에 사용할 수 있으며 그 전에 호출하는 경우 null을 반환한다.
브로드캐스트 리시버는 브로드캐스트가 올 때 호출되는 onReceive(…)에서 파라미터로 Context를 건네준다.
액티비티 컨텍스트(context-activity)보다 어플리케이션 컨텍스트(context-application)를 쓰라는 말이 있다.
가장 큰 이유는 메모리 릭(Memory leaks) 때문이다. 이 글의 요약만 옮기면, 컨텍스트와 관련된 메모리 릭을 피하기 위해 액티비티 컨텍스트에는 수명이 긴(long-lived) 참조를 피하고, 사용이 가능하다면 어플리케이션 컨텍스트를 사용하라고 권장하고 있다.
사용이 가능한 경우라고 전제를 단 이유는, 컨텍스트마다 제약 사항이 다르기 때문이다. 예를 들어, 다이얼로그나 액티비티 시작, 레이아웃 인플레이트는 액티비티 컨텍스트를 사용했을 때만 가능하거나 예상한 대로 사용할 수 있다. 현재 패키지의 이름을 가져오거나, 서비스 바인딩과 같은 어플리케이션 간 연결에는 어플리케이션 컨텍스트를 쓰는 것이 좋다.
여기에 대해서는 이 글을 읽어보자.
그럼, 액티비티 컨텍스트(context-activity)는 필요없나?
위에 언급되었지만, 안드로이드 개발자라면 한 번쯤 봤을 BadTokenException 는 다이얼로그를 생성할 때 어플리케이션 컨텍스트를 사용하면 발생한다. 다이얼로그는 액티비티 컨텍스트를 통해서만 만들 수 있기 때문이다.
레이아웃이나 메뉴, 위젯을 만들거나 다른 액티비티를 시작하는 경우, 프리퍼런스를 참조하거나 액티비티 클래스에서 제공하는 메소드를 사용할 때는 액티비티 컨텍스트를 사용하는 것이 좋다.
참조
- https://possiblemobile.com/2013/06/context/
- http://stackoverflow.com/questions/1026973/whats-the-difference-between-the-various-methods-to-get-a-context
- http://stackoverflow.com/questions/10641144/difference-between-getcontext-getapplicationcontext-getbasecontext-and
- http://android-developers.blogspot.com.tr/2009/01/avoiding-memory-leaks.html
- http://developer.android.com/intl/ko/reference/android/view/WindowManager.BadTokenException.html
- http://blog.naver.com/PostView.nhn?blogId=huewu&logNo=110085457720
좋은 글 감사합니다!
와주셔서 감사해요 😉
와
헤헤