2013-06-02 27 views
2

我想实现的方向变化后的DialogPreference有两个NumberPicker对象,恢复上次更改NumberPicker值:的Android DialogPreference NullPointerException异常在onRestoreInstanceState

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); 
} 

}

有两个问题:

  1. 应用程序崩溃,当我打开我的自定义首选项,更改其中一个采摘器上的值,然后腐烂将手机从纵向拍摄到风景。错误是NuLLpointerException,它指向我尝试将恢复的值分配给我的NumberPicker对象之一的行。
  2. 这是一个问题而不是问题。我从Android Developer主页复制了BaseSavedState内部类以及onSaveInstanceState(),onRestoreInstanceState()函数,但是当我尝试应用程序以恢复方向更改值时,手机显示了持续值,而不是方向更改前的最新值。当我试图用日志消息检查代码时,我发现我的手机在SaveInstanceState isPersisted检查退出函数并且不与BaseSavedState对象att一起操作。我想知道这是isPersisted检查,所以现在我可以保存和检索BaseSavedState对象的值,但之后,问题nr。 1出现。所以我的问题是,如果首选项是持久性的,跳过BaseSavedState对象创建的原因是什么。我的决定是跳过持续检查并强制应用程序创建BaseSavedState对象为坏的对象?

回答

0

我发现第一个问题的解决方案: 为了避免NullPointerException异常,我不得不封闭功能,即接入NumberPicker对象,有检查,确定是否这些拾荒者被启动。我有这个问题,因为在我的应用程序,我有多个我的自定义首选项实例,当我试图按照保存/恢复功能的数据路径,我发现,在logcat中我有我自己的消息的两倍(不仅我的屏幕偏好,但也使用我的自定义DialogPreference类的其他prefrerence)。而且,因为我只打开了一个首选项,所以在其他首选项中对NumberPicker对象的初始化没有发生,因此访问这些采集器(如果我理解正确的话)会导致NullPointerException。 但我仍然想听到更有经验的人,这可以解释保存/恢复功能的默认行为。

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> 
相关问题