From de0c99e89bfe2df43e363f2521c55d5da166ddad Mon Sep 17 00:00:00 2001 From: Andrew Solovay Date: Mon, 12 May 2014 19:50:37 -0700 Subject: [PATCH] Noted that OnSharedPreferenceChangeListener does not store a strong reference to the listener. Because of this, the listener is susceptible to garbage collection unless the caller preserves a strong reference to it. We suggest that the caller store a reference to the listener in an instance field of an object that will exist as long as the listener is needed. Also fixed code sample formatting in Settings.jd (some lines were overlong). Docs are staged in: http://asolovay.mtv:8901/guide/topics/ui/settings.html#Listening http://asolovay.mtv:8901/reference/android/content/SharedPreferences.html#registerOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener) Bug: 10437648 Change-Id: I48f5b87fa2ca7a240661d0cc00114d225819d54d --- .../android/content/SharedPreferences.java | 9 +++- docs/html/guide/topics/ui/settings.jd | 42 +++++++++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java index d4f7f06b008d1..00c2d8f78055e 100644 --- a/core/java/android/content/SharedPreferences.java +++ b/core/java/android/content/SharedPreferences.java @@ -355,7 +355,14 @@ public interface SharedPreferences { /** * Registers a callback to be invoked when a change happens to a preference. - * + * + *

Caution: The preference manager does + * not currently store a strong reference to the listener. You must store a + * strong reference to the listener, or it will be susceptible to garbage + * collection. We recommend you keep a reference to the listener in the + * instance data of an object that will exist as long as you need the + * listener.

+ * * @param listener The callback that will run. * @see #unregisterOnSharedPreferenceChangeListener */ diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd index d96447dc032f8..30b7eecc785fb 100644 --- a/docs/html/guide/topics/ui/settings.jd +++ b/docs/html/guide/topics/ui/settings.jd @@ -820,7 +820,8 @@ public class SettingsActivity extends PreferenceActivity public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType"; ... - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { if (key.equals(KEY_PREF_SYNC_CONN)) { Preference connectionPref = findPreference(key); // Set summary to be the user-description for the selected value @@ -863,7 +864,40 @@ protected void onPause() { } +

Caution: When you call {@link +android.content.SharedPreferences#registerOnSharedPreferenceChangeListener +registerOnSharedPreferenceChangeListener()}, the preference manager does not +currently store a strong reference to the listener. You must store a strong +reference to the listener, or it will be susceptible to garbage collection. We +recommend you keep a reference to the listener in the instance data of an object +that will exist as long as you need the listener.

+

For example, in the following code, the caller does not keep a reference to +the listener. As a result, the listener will be subject to garbage collection, +and it will fail at some indeterminate time in the future:

+ +
+prefs.registerOnSharedPreferenceChangeListener(
+  // Bad! The listener is subject to garbage collection!
+  new SharedPreferences.OnSharedPreferenceChangeListener() {
+  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+    // listener implementation
+  }
+});
+
+ +

Instead, store a reference to the listener in an instance data field of an +object that will exist as long as the listener is needed:

+ +
+SharedPreferences.OnSharedPreferenceChangeListener listener =
+    new SharedPreferences.OnSharedPreferenceChangeListener() {
+  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+    // listener implementation
+  }
+};
+prefs.registerOnSharedPreferenceChangeListener(listener);
+

Managing Network Usage

@@ -1142,13 +1176,15 @@ protected Parcelable onSaveInstanceState() { final Parcelable superState = super.onSaveInstanceState(); // Check whether this Preference is persistent (continually saved) if (isPersistent()) { - // No need to save instance state since it's persistent, use superclass state + // No need to save instance state since it's persistent, + // use superclass state return superState; } // Create instance of custom BaseSavedState final SavedState myState = new SavedState(superState); - // Set the state's value with the class member that holds current setting value + // Set the state's value with the class member that holds current + // setting value myState.value = mNewValue; return myState; }