안드로이드를 개발하다보면 context를 자주 접하게 된다.
startActivity, getWindow,getString.. 등 여러가지 상황에서 마주하게 되는데 정확히 context가 무엇이라고 말할수 있을까??
사전적 의미로는 문맥, 맥락이라는 의미이다.
컨텍스트는 애플리케이션 리소스 및 클래스에 접근하기 위한 인터페이스를 제공하는 추상클래스이다.
다시말하자면 어떤 객체를 핸들링하기 위한 접근 수단이라고 할수있다.
예를들면 /res 디렉토리 아래에 있는 value, string, anim, font,navigation등등..에 접근할 수 있도록 하고 Activity 또는 Fragment에서 View를 동적으로 초기화할 수 있도록 한다.
또한 컨텍스트는 응용 프로그램 수준 작업을 수행하는 메서드도 제공한다.
예를들면 startActivity, intent수신,발신과 같은 작업을 할 때 사용한다.
컨텍스트는 추상클래스로 해당 메서드를 구현하려는 하위 클래스가 있어야 한다.
안드로이드는 ContextImpl이라는 클래스에서 이것을 구현하게 해준다.
아래와 같이 ContextWrapper라는 다른 클래스는 단순히 ContextImpl에 의해 구현된 메서드를 사용하고 해당 호출을 자체 하위클래스에 위임한다.
아래의 트리구조를 보면 자주 사용하는 activity, Application, Service는 모두 Context를 상속받고있음을 알 수 있고 따라서 해당 컴포넌트에서 리소스에 접근하거나 다른 컴포넌트의 제어를 원한다면 다른 컴포넌트의 Context를 얻어야함을 유추할 수 있다.
Frgament에서 context를 사용하다보면 requireActivity, getActivity, requireContext, getContext를
사용할 일이 자주 있다.
kotlin을 처음 배웠을때부터 require~~~를 습관적으로 쓰게끔 배워서 사용하고 있었지만 어느날 이게 무슨 차이가 있는지 궁금해졌다.
/**
* Return the {@link Context} this fragment is currently associated with.
*
* @see #requireContext()
*/
@Nullable
public Context getContext() {
return mHost == null ? null : mHost.getContext();
}
/**
* Return the {@link Context} this fragment is currently associated with.
*
* @throws IllegalStateException if not currently associated with a context.
* @see #getContext()
*/
@NonNull
public final Context requireContext() {
Context context = getContext();
if (context == null) {
throw new IllegalStateException("Fragment " + this + " not attached to a context.");
}
return context;
}
/**
* Return the {@link FragmentActivity} this fragment is currently associated with.
* May return {@code null} if the fragment is associated with a {@link Context}
* instead.
*
* @see #requireActivity()
*/
@Nullable
final public FragmentActivity getActivity() {
return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
/**
* Return the {@link FragmentActivity} this fragment is currently associated with.
*
* @throws IllegalStateException if not currently associated with an activity or if associated
* only with a context.
* @see #getActivity()
*/
@NonNull
public final FragmentActivity requireActivity() {
FragmentActivity activity = getActivity();
if (activity == null) {
throw new IllegalStateException("Fragment " + this + " not attached to an activity.");
}
return activity;
}
두 종류의 메서드들은 뒤의 ~~~을 반환한다.
context, activity.
하지만 그 둘의 null에 대한 처리는 다르다.
get---은 null일 경우 throw Exception을 하고
require---은 null일 경우 null을 반환한다.
Fragment의 Lifecycle안에서 activity를 호출할 때에는 null에 대한 확인 없이 requireActivity()를 사용하면 된다. 하지만 만약 그 외에서( I/O 콜백과 같은 상황 ) 호출을 하게 된다면 requireActivity()를 사용할때 null일경우의 excpetion을 받아서 처리하는 로직을 만들어야 할 것이다. 그렇지 않으면 activity!!를 사용하면 되지만 null일 경우 앱이 죽게 될 것이다.