====== registerOnSharedPreferenceChangeListener ====== ===== 概要 ===== [[http://developer.android.com/reference/android/content/SharedPreferences.html|SharedPreferences]]に対して変更があった場合に起動されるコールバックを、registerOnSharedPreferenceChangeLitener()関数で登録することができる。 しかし、この機能は実際にはあまり上手く機能しないケースが多い。 一般的に、Preferenceの変更には、PreferenceActivityを継承したクラスを作り、ユーザからの変更を受け付ける。 これに対して、多くの場合、Preferenceの変更を受け取り、対応した処理をしたいのは別のアクティビティであろう。 このようなケースの場合、PreferenceActivityを起動する以前に、メインのアクティビティの方で、コールバックを登録する。 しかし、そのような実装を行なっても、アクティビティがPreferenceActivityに遷移した時点で、コールバックがGCによって、回収されないことを保証できない。このため、コールバックは、呼ばれたり呼ばれなかったりしてしまう。 回避策はいくつかあるが、ここでは、PreferenceActivityをstartActivityForResult()で起動し、変更点をintent経由で戻すことで、メインアクティビティ側で処理する方法を示す。 ===== startActivityForResult()による起動 ===== PreferenceActivityの起動を、startActivity()ではなく、戻り値を受け取るstartActivityForResult()で行なう。 private static final int PREFERENCE_ACTIVITY = 1234; // 適当な値でいい ... Intent pi = new Intent(context, MyPreferenceActivity.class); startActivityForResult(pi, PREFERENCE_ACTIVITY); 単純にこれだけでよい。 ===== 変更点の受け取り ===== 受け取りは、メインアクティビティ側で、onActivityResult()をオーバライドして行なう。 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch(requestCode) { case PREFERENCE_ACTIVITY: if (resultCode == RESULT_OK) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreference(context); ArrayList results = data.getStringArrayListExtra("results"); if (results.contains("pref_xxx")) { // pref_xxx が更新された場合の処理 if (sp.getBoolean("pref_xxx", false)) { ... } if (reslts.contains("pref_yyy")) { ... } break; case ... } このようにする。 勿論、このように行なうためには、PreferenceActivityの方で、変更をチェックし、ArrayListに変更点をセットして戻すようにしなければならない。 ===== PreferenceActivity側の処理 ===== PreferenceActivity側では値の変更をチェックし、変更があったものについて、そのキーを返すことにする。 勿論、キーと値をペアにして返すような実装もあり得るだろう。 ここでは、キーだけを返すことにして、値は、処理する側で改めて読み出すことにする。 public class MyPreferences extends PreferenceActivity implements OnPreferenceChangeListener { ArrayList mChangedKeys; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mChangedKeys = new ArrayList(); addPreferencesFromResource(R.xml.prefs); // register callbacks findPreference("pref_xxx").setOnPreferenceChangeListener(this); findPreference("pref_yyy").setOnPreferenceChangeListener(this); ... (変更をチェックしたい項目を全て登録する。) ... } public boolean onPreferenceChange(Preference preference, Object newValue) { String key = preference.getKey(); mChangedKeys.remove(key); // to avoid duplicated items. mChangedKeys.add(key); return true; } @Override public void onBackPressed() { Intent data = new Intent(); data.putStringArrayListExtra("results", mChangedKeys); setResult(RESULT_OK, data); super.onBackPressed(); } } 簡単のためにOnChangePreferenceListenerを実装することにする。 onPreferenceChange()を内包することで、変更のあった項目を、findPreference("pref_xxx").setOnPreferenceChangeListener(this);のように、簡単に登録できる。 onPreferenceChange()は、キーをmChangedKeysに登録するが、このとき重複を避けるために、登録に先立ち削除をしておく。削除は存在しなければ何もしないので特にチェックをしなくていい。 最後に、Preferneceの画面から戻るためには、BACKキーで戻るのが一般的なので、onBackPressed()をオーバライドして、mChangedKeysを"results"というキーで戻すように設定する。 [[Androidに関して]]