앱 프로세스는 사용 가능한 메모리에 제한이 있다. 안드로이드 버전별로 메모리 제한에 차이가 있고, 단말별로도 다르다.
허니콤부터는 android:largeHeap
옵션을 쓸 수 있지만 단말에 따라 소용이 없거나 GC 시간이 오래 걸리거나 다른 앱의 실행에 악영향을 줄 수도 있다.
메모리 제한 때문에 앱의 실행에 문제가 있다면 앱은 프로세스를 분리할 수 있다. 프로세스를 분리하는 것은 각 컴포넌트 별로 가능하다.
프로세스를 분리하려면 AndroidManifest.xml에서 android:process
속성에 별도 프로세스명을 지정하면 된다. 일반적으로는 속성에는 ":remote"와 같이 콜런(:)을 사용한다. 액티비티, 서비스, 콘텐트 프로바이더, 브로드캐스트 리시버 모두 프로세스를 분리하는게 가능하다.
하나의 앱에서 생성된 별도의 프로세스는 pid(process id)는 다르지만, 동일한 uid(user id)를 가지기 때문에 권한 문제없이 앱의 파일과 리소스에 접근할 수 있다.
Application도 AndroidManifest.xml에
android:process
값을 넣을 수 있는데, 이 값은 앱의 컴포넌트가 실행되는 기본 프로세스를 이야기하는 것으로 프로세스 분리와는 의미가 다르고 쓸 일이 많지 않다.
이 process에 값을 넣는 것은 시스템앱에서 가끔 사용된다.
ex)com.android.providers.media
앱 설정에서 android:process="android.process.media"
com.android.providers.telephony
는 android:process="com.android.phone"으로 되어 있다.
예를 들어, 사진공유 앱에서 기본 카메라 앱을 실행시키지 않고 자신의 CameraActivity를 가지고 있는 경우가 있다. 이때 CameraActivity는 메모리를 많이 사용하기 때문에 별도 프로세스로 분리하는 것이 낫다.
서비스가 독립적인 부분이 많다면 서비스를 분리하는게 낫다. 만일 서비스에 DB 작업이 많다면 DB 락 문제 떄문에 콘텐트 프로바이더를 도입해야 아므로, 작업이 복잡해질 경우 액티비티를 분리하는 게 좋겠다. 케이스별로 다르다!
컴포넌트의 프로세스를 분리하면 Application은 각 프로세스마다 새로 시작된다. 프로세스가 달라지면 Zygote에 의해서 fork된 이후에 ActivityThread를 새로 시작하고 Application을 새로 생성하는 것이다.
컴포넌트가 프로세스 분리되어 있더라도 Application만은 어느 프로세스에서도 한 번은 실행되어야 한다.
분리된 별도 프로세스에서는 데이터를 가져올 수 없다.
값을 공유하기 위해서 SharedPreferences
또는 DB를 사용해야 한다.
SharedPreferences는 어차피 xml 파일에서 읽어오는 것이기 때문에 한 번 읽어오는 것은 문제가 되지 않는다. 그런데 다른 프로세스에서 변경한 값을 다시 가져오는 문제는 단순하지 않다. 허니콤 이후에는 getSharedPreferences
메서드를 사용할때 Context.MODE_PRIVATE
이 전달되면 값을 제대로 가져올 수 없다.
물론 이 mode를 Context.MODE_MULTI_PROCESS
로 바꾸기만 하면, 된다지만 마시멜로부터 이 모드 지원을 중단했다.
결론적으로는 SharedPreferences를 다시 콘텐트 프로바이더로 감싸서 다른 프로세스에서 접근하는 방법이 권장된다. 이때 갱신이 가능하게 하려면 ContentObserver를 등록해서 데이터가 변경될 때 재조회하면 된다.