在这里学习安卓代码。我不确定我缺少什么,但我正在尝试创建一个使用DialogPreference
的自定义NumberPicker
,让用户选择年份。我试图关注android的Settings Guide,但我选择的值不能保存。只要我不退出应用程序,它就会保存,但如果我退出,那么当我重新启动应用程序时它会重置为默认值。我错过了什么?
SettingsActivity代码:
public class SettingsActivity extends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
}
public static class MyPreferenceFragment extends PreferenceFragment
{
@Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.app_preferences);
}
}
}
app_preferences.xml(SettingsActivity的布局)
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<EditTextPreference />
<com.NsouthProductions.gradetrackerpro.SemesterPickerPreference
android:key="MY_PICKER"
android:title="@string/year_pref_str"
android:summary="Choose a year here"
android:defaultValue="2005"
/>
</PreferenceScreen>
SemesterPickerPreference(DialogPreference的扩展名)
public class SemesterPickerPreference extends DialogPreference {
private int year;
private NumberPicker semPick;
private int DEFAULT_VALUE;
public SemesterPickerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
DEFAULT_VALUE = 2003;
setDialogLayoutResource(R.layout.semester_picker_dialog);
setPositiveButtonText(android.R.string.ok);
setNegativeButtonText(android.R.string.cancel);
setDialogIcon(null);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
persistInt(semPick.getValue());
}
}
@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
if (restorePersistedValue) {
// Restore existing state
year = this.getPersistedInt(DEFAULT_VALUE);
} else {
// Set default state from the XML attribute
year = (Integer) defaultValue;
persistInt(year);
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getInteger(index, DEFAULT_VALUE);
}
@Override
protected View onCreateDialogView() {
int max = 2038;
int min = 2001;
LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.semester_picker_dialog, null);
semPick = (NumberPicker) view.findViewById(R.id.semester_picker);
// Initialize state
semPick.setMaxValue(max);
semPick.setMinValue(min);
semPick.setValue(this.getPersistedInt(DEFAULT_VALUE));
semPick.setWrapSelectorWheel(false);
return view;
}
// This code copied from android's settings guide.
private static class SavedState extends BaseSavedState {
// Member that holds the setting's value
// Change this data type to match the type saved by your Preference
int value;
public SavedState(Parcelable superState) {
super(superState);
}
public SavedState(Parcel source) {
super(source);
// Get the current preference's value
value = source.readInt(); // Change this to read the appropriate data type
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
// Write the preference's value
dest.writeInt(value); // Change this to write the appropriate data type
}
// Standard creator object using an instance of this class
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
@Override
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
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
myState.value = year;
return myState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
// Check whether we saved the state in onSaveInstanceState
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save the state, so call superclass
super.onRestoreInstanceState(state);
return;
}
// Cast state to custom BaseSavedState and pass to superclass
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
// Set this Preference's widget to reflect the restored state
semPick.setValue(myState.value);
}
}
semester_picker_dialog.xml(我的学期/年度选择器的布局)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_horizontal" >
<NumberPicker
android:id="@+id/semester_picker"
android:layout_centerInParent="true"
android:layout_width="100dip"
android:layout_height="match_parent" />
</LinearLayout>
答案 0 :(得分:2)
您在首选项XML中缺少android:persistent="true" XML属性。这就是告诉Preference是否将其值实际存储到共享首选项的原因。调用PersistInt()
显然是不够的。
答案 1 :(得分:0)
我有类似的问题。我尝试了@scott的这个android:persistent="true"
解决方案,但它没有用。我做了一点挖掘,我在EditTextPreference
课程中找到了解决方案。
package android.preference;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.EditText;
/**
* A {@link Preference} that allows for string
* input.
* <p>
* It is a subclass of {@link DialogPreference} and shows the {@link EditText}
* in a dialog. This {@link EditText} can be modified either programmatically
* via {@link #getEditText()}, or through XML by setting any EditText
* attributes on the EditTextPreference.
* <p>
* This preference will store a string into the SharedPreferences.
* <p>
* See {@link android.R.styleable#EditText EditText Attributes}.
*/
public class EditTextPreference extends DialogPreference {
/**
* The edit text shown in the dialog.
*/
private EditText mEditText;
private String mText;
public EditTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mEditText = new EditText(context, attrs);
// Give it an ID so it can be saved/restored
mEditText.setId(com.android.internal.R.id.edit);
/*
* The preference framework and view framework both have an 'enabled'
* attribute. Most likely, the 'enabled' specified in this XML is for
* the preference framework, but it was also given to the view framework.
* We reset the enabled state.
*/
mEditText.setEnabled(true);
}
public EditTextPreference(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.editTextPreferenceStyle);
}
public EditTextPreference(Context context) {
this(context, null);
}
/**
* Saves the text to the {@link SharedPreferences}.
*
* @param text The text to save
*/
public void setText(String text) {
final boolean wasBlocking = shouldDisableDependents();
mText = text;
persistString(text);
final boolean isBlocking = shouldDisableDependents();
if (isBlocking != wasBlocking) {
notifyDependencyChange(isBlocking);
}
}
/**
* Gets the text from the {@link SharedPreferences}.
*
* @return The current preference value.
*/
public String getText() {
return mText;
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
EditText editText = mEditText;
editText.setText(getText());
ViewParent oldParent = editText.getParent();
if (oldParent != view) {
if (oldParent != null) {
((ViewGroup) oldParent).removeView(editText);
}
onAddEditTextToDialogView(view, editText);
}
}
/**
* Adds the EditText widget of this preference to the dialog's view.
*
* @param dialogView The dialog view.
*/
protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
ViewGroup container = (ViewGroup) dialogView
.findViewById(com.android.internal.R.id.edittext_container);
if (container != null) {
container.addView(editText, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
String value = mEditText.getText().toString();
if (callChangeListener(value)) {
setText(value);
}
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setText(restoreValue ? getPersistedString(mText) : (String) defaultValue);
}
@Override
public boolean shouldDisableDependents() {
return TextUtils.isEmpty(mText) || super.shouldDisableDependents();
}
/**
* Returns the {@link EditText} widget that will be shown in the dialog.
*
* @return The {@link EditText} widget that will be shown in the dialog.
*/
public EditText getEditText() {
return mEditText;
}
/** @hide */
@Override
protected boolean needInputMethod() {
// We want the input method to show, if possible, when dialog is displayed
return true;
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
// No need to save instance state since it's persistent
return superState;
}
final SavedState myState = new SavedState(superState);
myState.text = getText();
return myState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
return;
}
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
setText(myState.text);
}
private static class SavedState extends BaseSavedState {
String text;
public SavedState(Parcel source) {
super(source);
text = source.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(text);
}
public SavedState(Parcelable superState) {
super(superState);
}
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
首先,您不会在onRestoreInstanceState
方法中保存状态,只需将文字设置为图形semPick.setValue(myState.value);
即可。另外,请检查方法onDialogClosed
和onSetInitialValue
。
经过测试和工作。
答案 2 :(得分:0)
如何移动以下行:
getFragmentManager()。beginTransaction()。replace(android.R.id.content,new MyPreferenceFragment())。commit();
出自SettingsActivity的oncreate方法。您想在设置首选项后调用该行代码? 您可以在退出设置活动时执行此操作,或者使用setOnPreferenceChangeListener(取决于首选项的类型)。但对于numberpicker控件,我会使用前者