2013-06-02 63 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> 
相關問題