我正在尝试使用两个DialogPreference
个对象来实现NumberPicker
,这会在更改方向后恢复上次更改的NumberPicker
值:
public class CustomTimePreference extends DialogPreference {
public NumberPicker firstPicker, secondPicker;
private int lastHour = 0;
private int lastMinute = 15;
private int firstMaxValue;
private int tempHour;
private int tempMinute;
private int rotatedHour;
private int rotatedMinute;
private int firstMinValue = 0;
private int secondMinValue=0;
private int secondMaxValue=59;
private String headerText;
private boolean usedForApprox;
public static int getHour(String time){
String[] pieces = time.split(":");
return (Integer.parseInt(pieces[0]));
}
public static int getMinute(String time){
String[] pieces = time.split(":");
return (Integer.parseInt(pieces[1]));
}
public CustomTimePreference(Context context){
this(context, null);
}
public CustomTimePreference(Context context, AttributeSet attrs){
super(context, attrs);
init(attrs);
setDialogLayoutResource(R.layout.custom_time_preference);
setPositiveButtonText(context.getString(R.string.time_preference_set_text));
setNegativeButtonText(context.getString(R.string.time_preference_cancel_text));
}
private void init(AttributeSet attrs){
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CustomTimePreference);
firstMaxValue = a.getInteger(R.styleable.CustomTimePreference_firstMaxValue,10);
usedForApprox = a.getBoolean(R.styleable.CustomTimePreference_usedForApproximate, false);
headerText = a.getString(R.styleable.CustomTimePreference_customTimeDialogTopText);
a.recycle();
}
public void setFirstPickerValue(int value){
firstPicker.setValue(value);
}
public void setSecondPickerValue(int value){
secondPicker.setValue(value);
}
@Override
protected View onCreateDialogView(){
Log.d("OnCreateDialogView","nanana");
View root = super.onCreateDialogView();
TextView tv = (TextView)root.findViewById(R.id.custom_time_preference_title);
tv.setText(headerText);
firstPicker = (NumberPicker)root.findViewById(R.id.time_preference_first_picker);
firstPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// TODO Auto-generated method stub
tempHour = newVal;
}
});
secondPicker = (NumberPicker)root.findViewById(R.id.time_preference_second_picker);
secondPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// TODO Auto-generated method stub
tempMinute = newVal;
}
});
if(usedForApprox){
int smallestValue = MainActivity.getShortestPeriodLength(getContext());
int second = smallestValue % 60;
second-=1;
firstPicker.setMaxValue(second);
secondPicker.setMaxValue(59);
} else {
firstPicker.setMaxValue(firstMaxValue);
secondPicker.setMaxValue(secondMaxValue);
}
firstPicker.setMinValue(firstMinValue);
secondPicker.setMinValue(secondMinValue);
return root;
}
@Override
protected void onBindDialogView(View v){
super.onBindDialogView(v);
firstPicker.setValue(lastHour);
secondPicker.setValue(lastMinute);
}
@Override
protected void onDialogClosed(boolean positiveResult){
super.onDialogClosed(positiveResult);
if(positiveResult){
lastHour = firstPicker.getValue();
lastMinute = secondPicker.getValue();
if (lastHour ==0 && lastMinute == 0){
lastMinute =1;
}
String time = String.valueOf(lastHour) + ":" + String.valueOf(lastMinute);
if(callChangeListener(time)){
persistString(time);
}
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index){
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue){
String time = null;
if(restoreValue){
if (defaultValue == null){
time = getPersistedString("00:00");
} else {
time = getPersistedString(defaultValue.toString());
}
} else {
time = defaultValue.toString();
}
lastHour = tempHour = getHour(time);
lastMinute = tempMinute = getMinute(time);
}
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
String value;
public SavedState(Parcelable superState) {
super(superState);
}
public SavedState(Parcel source) {
super(source);
// Get the current preference's value
value = source.readString(); // 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.writeString(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 = String.valueOf(tempHour) + ":" + String.valueOf(tempMinute);
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
rotatedHour = getHour(myState.value);
rotatedMinute = getMinute(myState.value);
firstPicker.setValue(rotatedHour);
secondPicker.setValue(rotatedMinute);
}
}
有两个问题:
NuLLpointerException
,它指向我尝试将已恢复的值分配给我的NumberPicker
个对象的行。答案 0 :(得分:1)
使用3个NumberPicker
对象查看此实现:
package com.bom.dom;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.NumberPicker;
import android.widget.NumberPicker.OnValueChangeListener;
public class TimePreference extends DialogPreference {
NumberPicker hoursNumberPicker;
NumberPicker minutesNumberPicker;
NumberPicker secondsNumberPicker;
int time;
int currentTime;
public TimePreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onBindDialogView(View view) {
hoursNumberPicker = (NumberPicker) view.findViewById(R.id.numberpicker_hours);
hoursNumberPicker.setMaxValue(24);
hoursNumberPicker.setMinValue(0);
hoursNumberPicker.setOnValueChangedListener(new OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
updateCurrentTimeFromUI();
}
});
minutesNumberPicker = (NumberPicker) view.findViewById(R.id.numberpicker_minutes);
minutesNumberPicker.setMaxValue(59);
minutesNumberPicker.setMinValue(0);
minutesNumberPicker.setOnValueChangedListener(new OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
updateCurrentTimeFromUI();
}
});
secondsNumberPicker = (NumberPicker) view.findViewById(R.id.numberpicker_seconds);
secondsNumberPicker.setMaxValue(59);
secondsNumberPicker.setMinValue(0);
secondsNumberPicker.setOnValueChangedListener(new OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
updateCurrentTimeFromUI();
}
});
updateUI();
super.onBindDialogView(view);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
time = currentTime;
persistInt(time);
return;
}
currentTime = time;
}
private void updateCurrentTimeFromUI() {
int hours = hoursNumberPicker.getValue();
int minutes = minutesNumberPicker.getValue();
int seconds = secondsNumberPicker.getValue();
currentTime = hours * 3600 + minutes * 60 + seconds;
}
@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
if (restorePersistedValue) {
time = getPersistedInt(1);
} else {
time = (Integer) defaultValue;
persistInt(time);
}
currentTime = time;
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
Integer defaultValue = a.getInteger(index, 1);
return defaultValue;
}
private void updateUI() {
int hours = (int) (currentTime / 3600);
int minutes = ((int) (currentTime / 60)) % 60;
int seconds = currentTime % 60;
hoursNumberPicker.setValue(hours);
minutesNumberPicker.setValue(minutes);
secondsNumberPicker.setValue(seconds);
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
final SavedState myState = new SavedState(superState);
myState.value = currentTime;
return myState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state == null || !state.getClass().equals(SavedState.class)) {
super.onRestoreInstanceState(state);
return;
}
SavedState myState = (SavedState) state;
currentTime = myState.value;
super.onRestoreInstanceState(myState.getSuperState());
}
private static class SavedState extends BaseSavedState {
int value;
public SavedState(Parcelable superState) {
super(superState);
}
public SavedState(Parcel source) {
super(source);
value = source.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(value);
}
@SuppressWarnings("unused")
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];
}
};
}
}
布局文件是:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<NumberPicker
android:id="@+id/numberpicker_hours"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<NumberPicker
android:id="@+id/numberpicker_minutes"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<NumberPicker
android:id="@+id/numberpicker_seconds"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
答案 1 :(得分:0)
我找到了第一个问题的解决方案: 为了避免NullPointerException,我必须使用检查来附加访问NumberPicker对象的函数,以确定是否启动了这些选择器。我有这个问题,因为在我的应用程序上我有多个我的自定义首选项实例,当我尝试按照数据路径保存/恢复功能时,我发现,在logcat中,我的数量是我自己的两倍(不仅仅是我的屏幕偏好,也适用于使用我的自定义DialogPreference类的其他prefrerence)。因为,我只打开了一个首选项,在其他首选项中初始化NumberPicker对象并没有发生,因此访问这些选择器(如果我理解正确)导致NullPointerException。 但我仍然希望听到更有经验的人,这可以解释保存/恢复功能的默认行为。