지금 진행 중인 프로젝트에서 신기한 증상이 있는데, service가 multi process가 아니면 최초 실행 시 딱 한 번 동작을 안하는 오류가 있다.
앱을 최초로 실행했거나, 폰을 껐다가 켜서 서비스가 재시작 됐을 때에 나타난다.
다른 건 문제가 없었는데, 유독 preference에 저장된 값이 공유가 안되는 문제가 나타났다.
먼저 서비스의 process에 :remote를 넣었다.
<service android:name="kr.mint.testdesignpattern.MainService" android:process=":remote" />
그리고 값을 저장할 기본이 되는 클래스를 mode_multi_process로 수정했다.
public class BasePreferenceHelper { private SharedPreferences _sharedPreferences; protected BasePreferenceHelper(Context $context) { super(); _sharedPreferences = $context.getSharedPreferences($context.getPackageName(), Context.MODE_MULTI_PROCESS); } private SharedPreferences.Editor editor() { return _sharedPreferences.edit(); } protected void put(String $key, String $value) { editor().putString($key, $value).commit(); } protected String get(String $key) { return _sharedPreferences.getString($key, null); } protected void put(String $key, boolean $value) { editor().putBoolean($key, $value).commit(); } protected boolean get(String $key, boolean $default) { return _sharedPreferences.getBoolean($key, $default); } protected void put(String $key, int $value) { editor().putInt($key, $value).commit(); } protected int get(String $key, int $default) { return _sharedPreferences.getInt($key, $default); } protected void put(String $key, Set<String> $set) { editor().putStringSet($key, $set).commit(); } protected Set<String> getStringSet(String $key) { return _sharedPreferences.getStringSet($key, null); } }
그 다음에 실제 코드에서 호출할 preference helper를 약간 바꿨다.
처음에는 singleton이었던 클래스가 이젠 이도저도 아닌게 돼버렸다….
public class TestPreferenceHelper extends BasePreferenceHelper { private static final String PROPERTY_APP_VERSION = "appVersion"; public static synchronized TestPreferenceHelper instance(Context $context) { return new TestPreferenceHelper($context); } public TestPreferenceHelper(Context $context) { super($context); } public void putAppVersion(int $appVersion) { put(PROPERTY_APP_VERSION, $appVersion); } public int appVersion() { return get(PROPERTY_APP_VERSION, 0); } }
메인으로 돌아갈 서비스에서도 수정할 부분이 있다.
예전에는 전역으로 선언한 preference helper 변수를 사용했지만, 이젠 매번 새로운 인스턴스를 호출해야한다…
public class MainService extends Service { @Override public void onCreate() { super.onCreate(); IntentFilter filter = new IntentFilter(); filter.addAction("asdf"); registerReceiver(broadcastReceiver, filter); } @Override public void onDestroy() { super.onDestroy(); unregisterReceiver(broadcastReceiver); } private void show() { Log.i("MainService.java | show", "222|" + TestPreferenceHelper.instance(getApplicationContext()).appVersion()); } /************************************************** * broadcast receiver ***************************************************/ private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context $context, Intent $intent) { String action = $intent.getAction(); if ("asdf".equals(action)) { Log.i("MainService.java | onReceive", "111|" + TestPreferenceHelper.instance(getApplicationContext()).appVersion()); show(); } } }; /************************************************** * useless ***************************************************/ @Override public IBinder onBind(Intent arg0) { return null; } }
편의를 위해 메뉴 클릭하면 신호가 가게 했다.
여기에서도 매번 새로운 인스턴스를 호출해야한다.
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startService(new Intent(getApplicationContext(), MainService.class)); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { int appVersion = TestPreferenceHelper.instance(getApplicationContext()).appVersion(); appVersion++; TestPreferenceHelper.instance(getApplicationContext()).putAppVersion(appVersion); Log.i("MainActivity.java | onOptionsItemSelected", "000|" + TestPreferenceHelper.instance(getApplicationContext()).appVersion() + "|"); Intent intent = new Intent("asdf"); sendBroadcast(intent); } return super.onOptionsItemSelected(item); } }
MainActivity.java | onOptionsItemSelected: 000|159| MainService.java | onReceive: 111|159 MainService.java | show: 222|159
평소 같았으면 이런 코드를 쓰는 건 견딜 수 없을 정도로 신경이 쓰이는데, 아직 다른 방법을 찾지 못했다…