Android 使用NumberPicker作为对话框首选项。为什么赢了';我的设置不能保存吗?

Android 使用NumberPicker作为对话框首选项。为什么赢了';我的设置不能保存吗?,android,settings,sharedpreferences,numberpicker,dialog-preference,Android,Settings,Sharedpreferences,Numberpicker,Dialog Preference,在这里学习android代码。我不确定我遗漏了什么,但我正在尝试创建一个自定义的对话框preference,它使用NumberPicker让用户选择年份。我试着跟随android,但我选择的值没有保存。只要我不退出应用程序,它就会保存,但如果我退出,则在我重新启动应用程序时,它会重置为默认值。我错过了什么 设置活动代码: public class SettingsActivity extends PreferenceActivity { @Override public v

在这里学习android代码。我不确定我遗漏了什么,但我正在尝试创建一个自定义的
对话框preference
,它使用
NumberPicker
让用户选择年份。我试着跟随android,但我选择的值没有保存。只要我不退出应用程序,它就会保存,但如果我退出,则在我重新启动应用程序时,它会重置为默认值。我错过了什么

设置活动代码:

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(设置活动的布局)


SemesterPickerPreference(DialogPreference的扩展)

公共类SemesterPickerPreference扩展了DialogPreference{
私人国际年;
私人电话窃听器;
私有int默认值;
公共符号集引用(上下文、属性集属性){
超级(上下文,attrs);
默认_值=2003;
setDialogLayoutResource(R.layout.Semmer\u picker\u对话框);
setPositiveButtonText(android.R.string.ok);
setNegativeButtonText(android.R.string.cancel);
setDialogIcon(空);
}
@凌驾
受保护的无效onDialogClosed(布尔正结果){
如果(正结果){
persistin(semPick.getValue());
}
}
@凌驾
SetInitialValue上受保护的void(布尔restorePersistedValue,对象defaultValue){
if(restorePersistedValue){
//恢复现有状态
年份=this.getPersistedInt(默认值);
}否则{
//从XML属性设置默认状态
年份=(整数)默认值;
持续(年);
}
}
@凌驾
受保护对象onGetDefaultValue(类型Darray a,整数索引){
返回一个.getInteger(索引,默认值);
}
@凌驾
受保护的视图onCreateDialogView(){
int max=2038;
int min=2001;
充气机=
(LayoutFlater)getContext().getSystemService(Context.LAYOUT\u充气机\u服务);
视图=充气机。充气(R.layout.Semmer\u picker\u对话框,空);
semPick=(NumberPicker)view.findviewbyd(R.id.semerm\u picker);
//初始化状态
semPick.setMaxValue(最大值);
semPick.setMinValue(最小值);
setValue(this.getPersistedInt(默认值));
semPick.setWrapSelectorWheel(假);
返回视图;
}
//此代码复制自android的设置指南。
私有静态类SavedState扩展了BaseSavedState{
//保存设置值的成员
//更改此数据类型以匹配您的首选项保存的类型
int值;
公共存储状态(可包裹超级状态){
超级(超级国家);
}
公共存储状态(地块源){
超级(来源);
//获取当前首选项的值
value=source.readInt();//将其更改为读取适当的数据类型
}
@凌驾
公共无效写入包裹(包裹目的地,内部标志){
超级可写包裹(目的地、旗帜);
//写入首选项的值
dest.writeInt(值);//将其更改为写入适当的数据类型
}
//使用此类实例的标准创建者对象
公共静态最终包裹。创建者=
新建Parcelable.Creator(){
public SavedState createFromParcel(中的地块){
返回新的SavedState(in);
}
public SavedState[]新数组(整数大小){
返回新的SavedState[大小];
}
};
}
@凌驾
受保护的地块onSaveInstanceState(){
最终可包裹超级状态=super.onSaveInstanceState();
//检查此首选项是否持续(持续保存)
if(isPersistent()){
//无需保存实例状态,因为它是持久的,请使用超类状态
回归超级国家;
}
//创建自定义BaseSavedState的实例
最终SavedState myState=新SavedState(超级状态);
//使用保存当前设置值的类成员设置状态值
myState.value=年;
返回我的国家;
}
@凌驾
RestoreInstanceState上的受保护无效(可包裹状态){
//检查是否将状态保存在onSaveInstanceState中
if(state==null | |!state.getClass().equals(SavedState.class)){
//没有保存状态,所以调用超类
super.onRestoreInstanceState(状态);
返回;
}
//将状态强制转换为自定义BaseSavedState并传递给超类
SavedState myState=(SavedState)状态;
super.onRestoreInstanceState(myState.getSuperState());
//设置此首选项的小部件以反映恢复的状态
semPick.setValue(myState.value);
}
}
学期选择器dialog.xml(我的学期/年度选择器的布局)


首选项XML中缺少XML属性。这就是告诉首选项是否实际将其值存储到共享首选项的原因。调用
persistin()
显然是不够的。

我也遇到了类似的问题。我从@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];
            }
        };
    }

}
package.preference;
导入android.content.Context;
导入android.content.SharedReferences;
导入android.content.res.TypedArray;
导入android.os.packet;
导入android.os.Parcelable;
导入android.text.TextUtils;
导入android.util.AttributeSet;
导入android.view.view;
导入android.view.ViewGroup;
导入android.view.ViewParent;
导入android.widget.EditText;
/**
*允许使用字符串的{@link Preference}
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);
    }
}
<?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>
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];
            }
        };
    }

}