SharedPreferences.OnSharedPreferenceChangeListener 採用 WeakHashMap 儲存監聽器,導致匿名內部類實例在方法結束後隨即符合 GC 回收條件,造成監聽器「前幾次生效、隨後失效」的詭異現象。核心解決之道是「以強引用持有監聽器實例」。
// 錯誤:監聽器實例無強引用,極易被 GC 回收
prefs.registerOnSharedPreferenceChangeListener(
new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// 處理邏輯
}
}
);
public class MainActivity extends AppCompatActivity {
// 1. 宣告為成員變數,生命週期綁定 Activity
private SharedPreferences.OnSharedPreferenceChangeListener prefsListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
// 2. 實例化並賦值給成員變數
prefsListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
Log.d("PREFS", "Changed key: " + key);
}
};
// 3. 註冊
prefs.registerOnSharedPreferenceChangeListener(prefsListener);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 4. 解註冊(雖非修復核心,但屬良好習慣)
PreferenceManager.getDefaultSharedPreferences(this)
.unregisterOnSharedPreferenceChangeListener(prefsListener);
}
}
Android 7.0 引入 PreferenceDataStore 允許完全自訂儲存邏輯,可搭配 LiveData 或 Flow 實現更現代的觀察模式,徹底規避 WeakHashMap 陷阱。
「註冊的監聽器必須有強引用存活,直到明確解註冊為止。」
理解此機制,即可徹底解決 SharedPreferences 監聽器「莫名失效」的疑難雜症。