likejiujitsu likejiujitsu - 28 days ago 7
Android Question

My ListPreference does not persist values when changing screen orientation

I have been stuck on this for days and tried different workarounds.
When I change screen orientation, the preference summary loses its value.

I have a custom ListPreference which when user clicks, pops up two choices for buddy - myself, and some other (in the actual program, user selects a buddy from Contacts).

I set the summary to the selected buddy's email address.

clicking preference pops up list preference which, depending on what is clicked, shows myself, or contacts picker to select a buddy.

enter image description here

'myself' was selected

enter image description here

flipping phone loses buddy

enter image description here

Here is a working program stripped to show the essentials.

class BuddyPreference2

public class BuddyPreference2 extends ListPreference {
String buddy;
private static final String TAG = "REGU";

public BuddyPreference2(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
persistString((String) buddy);
}
super.onDialogClosed(positiveResult);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
super.onSetInitialValue(restoreValue, defaultValue);
if (restoreValue) {
// Restore existing state
buddy = this.getPersistedString("none set");
} else {
// Set default state from the XML attribute
buddy = (String) defaultValue;
persistString(buddy);
}
}
/*
* (non-Javadoc)
*
* @see android.preference.ListPreference#setValue(java.lang.String)
*/
@Override
public void setValue(String value) {
String s = new String(value);
super.setValue(s);
}
@Override
protected View onCreateDialogView() {
View view = super.onCreateDialogView();

return view;
}
}


user_prefs.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="@+id/pref_screen" >
<com.mypreferences.BuddyPreference2
android:entries="@array/buddy_entry"
android:entryValues="@array/buddy_value"
android:key="buddy_entry"
android:summary="my buddy"
android:title="my buddy" />
</PreferenceScreen>


class EditAlertPreferencesActivity

public class EditAlertPreferencesActivity extends Activity {


static final String BUDDY = "buddy_entry";

static final String TAG = "REGU";
private static final int CONTACT_PICKER_RESULT = 1001;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_prefs_fragment);
}

// Fragment that displays the mesg preference
public static class UserPreferenceFragment extends PreferenceFragment {

protected static final String TAG = "REGU";
private OnSharedPreferenceChangeListener mListener;
private Preference buddyPreference;

String myEmailAddress;

String getMyEmailAddress() {
return "Myself" + " <me@my.com>";
}

public void setBuddySummary(String s) {
buddyPreference.setSummary(s);
}


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myEmailAddress = getMyEmailAddress();

// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.user_prefs);

buddyPreference = (Preference) getPreferenceManager().findPreference(BUDDY);

buddyPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String buddyChoice = (String) newValue;
if (buddyChoice.equals(getString(R.string.select))) {
Toast.makeText(getActivity(), "pick a contact", Toast.LENGTH_SHORT);
pickContact();
} else {
buddyPreference.setSummary(myEmailAddress);
}
return false;
}
});

// Attach a listener to update summary when msg changes
mListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
if (key.equals(BUDDY)) {
buddyPreference.setSummary(sharedPreferences.getString(BUDDY, "none set"));
} else {
Log.e(TAG, "error; I do not recognize key " + key);
}
}
};

// Get SharedPreferences object managed by the PreferenceManager for
// this Fragment
SharedPreferences prefs = getPreferenceManager().getSharedPreferences();

// Register a listener on the SharedPreferences object
prefs.registerOnSharedPreferenceChangeListener(mListener);

// Invoke callback manually to display the msg
mListener.onSharedPreferenceChanged(prefs, BUDDY);
}

/*
* (non-Javadoc)
*
* @see android.preference.PreferenceFragment#onCreateView(android.view.
* LayoutInflater, android.view.ViewGroup, android.os.Bundle)
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}

public void pickContact() {
String buddyEmailAddress = "Some Buddy " + " <buddy@email.com>";
setBuddySummary(buddyEmailAddress);
}
}
}


user_prefs_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.mypreferences.EditAlertPreferencesActivity$UserPreferenceFragment"
android:orientation="vertical"
android:id="@+id/userPreferenceFragment">

</fragment>


arrays.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="buddy_entry">
<item>myself</item>
<item>select a contact</item>
</string-array>
<string-array name="buddy_value">
<item>myself</item>
<item>select</item>
</string-array>
</resources>


class PreferencesActivityExample

public class PreferencesActivityExample extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// Open a User Preferences Entry Activity
final Button button = (Button) findViewById(R.id.check_pref_button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(
PreferencesActivityExample.this,
EditAlertPreferencesActivity.class));
}
});

}
}


strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="select">select</string>
</resources>

Answer

Issue is that the Preference value selected on the dialog is not saved/updated. You can easily verify this Close the Activity and launch gain. You will still see the default value , noting to do with orientation change.

FIX: You need to return true to update the new value in preference.

@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
    // do all your other stuff here            
    return true;
}

True to update the state of the Preference with the new value.