참, 제목을 고르기 힘든데...

잠깐 상황을 설명하자면 Singleton (Utility class)에서 파라메터로 Context를 요구하는 메소드가 여럿 있는데, 이것 때문에 콜 스택에서 이것을 위해 몇 번이고 Context를 계속 넘겨줘야 하는 한다. 여기서 고민이 시작된다. 웬만하면 굳이 activity의 context가 없어도 application context만으로도 충분하니깐, application context를 어디에 저장해 두고 static method를 통해 가져오면 어떨까?


그래서 일반적으로 떠 올릴 수 있는 방법이 다음과 같다.


--- in AndroidManifest.xml ---

<application

android:name="MyApplication"

.

.

.



--- MyApplication.java ---

// The class name must be same to the name of application declared in AndroidManifest.xml

public class MyApplication extends Application {

private static Context sContext;


@Override

public void onCreate() {

super.onCreate();

sContext = getApplicationContext();

}


public static Context getAppContext() {

return sContext;

}

}


위와 같이 AndroidManifest.xml 파일의 <application> 에 android:name를 선언해 준다. 그리고 그와 같은 이름으로 Applciation을 상속받은 클래스를 만들고 onCreate()에서 Application Context를 static 변수에 저장을 한다. 이렇게 하면 Application이 시작될 때(다른 모든 컴포넌트들이 초기화 되는 것보다 빨리) Application Context가 초기화 되기 때문에 이 Context를 이용하여 Singleton을 초기화 하거나 혹은 다른 컴포넌트에서 Singleton을 이용할 때 Context에 대한 고민없이 이용할 수 도 있다.


그럴듯 해 보이지 않은가?

그런데 이렇게 작성하면 Static Field Leaks라는 android lint이슈가 발생한다.


말 그대로 Context 클래스를 static 필드에 저장하면 leak이 발생할 수 있다는 이야기다. 일반적으로 activity context를 어느 Singleton에 static으로 잡아 두었다고 생각해 보자. activity가 종료되어도 Singleton에 남아있는 activity에 대한 static reference 때문에 Application이 종료될 때 까지 activity가 Garbage Collection이 되지 않고 메모리에 남아 leak을 발생시킨다.


그런데 application context도 같을까? 안드로이드 팀에서 공식적으로 여기에 대해서 언급한 것은 없다. 다만 Application 클래스의 레퍼런스 문서를 보면 아래와 같은 내용이 나온다.


Note: There is normally no need to subclass Application. In most situations, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), include Context.getApplicationContext() as a Context argument when invoking your singleton's getInstance() method.


Application을 상속받아 global context를 이용해도 되는데, 그것 보다는 Context argument를 이용하는게 singleton을 더 모듈화할 수 있다고 적혀있다. 이걸로 유추했을 때, 위와 같이 이용해도 문제는 없으리라 생각된다.


또한, stackoverflow를 보면 저렇게 해도 문제가 없다는 의견이 많은 듯 하다. 다만 android core쪽에서 언제든 변경될 수 있기 때문에 지금은 문제가 없다 하더라도 미래를 생각하면 이용하지 않는 게 좋다는 것 같다.


회사의 다른 팀의 이야기를 들어봐도 위와 같이 이용했을 때, leak은 없었다는 이야기를 들었다.


결론적으로 나도 이 방법은 사용하지 않기로 하였다. 미래를 생각했을 때 공식적으로 인정받지 않은 로직을 피하고 싶기도 하고, Testability측면에서 모듈화 되어 있는 것이 더 낫다고 판단했다.



P.S

Application과 Activity의 생명주기에 대한 이해 없이 저 Context를 막 같다 쓸까봐 걱정되기도 했다.


반응형

설정

트랙백

댓글

  • 575 2016.12.21 14:21 답글 | 수정/삭제 | ADDR

    android:process 라는 tag를 써서 service를 별도의 process에서 수행한다거나 하면, 해당 service로 인해서 별도 process가 수행될 때, application 객체가 하나 더 만들어집니다.

    그래서 application context가 반드시 하나로만 유지되지는 않습니다. :)

    • BlogIcon 아자 2016.12.21 15:09 신고 수정/삭제

      그런 경우도 있을 수 있겠군요!
      멀티 프로세스인 경우가 그리 많지 않을 것 같긴 합니다만, 그 상황에서는 Application Context를 다룰 때는 주의해야 겠네요.

  • good 2020.02.14 12:14 답글 | 수정/삭제 | ADDR

    좋은 글 잘 봤습니다.
    같은 고민하고 있었는데 글이랑 댓글 보고 해결 됐습니다. good