gpt4 book ai didi

onRestoreInstanceState 中的 Android DialogPreference NullPointerException

转载 作者:行者123 更新时间:2023-11-29 01:52:55 27 4
gpt4 key购买 nike

我正在尝试使用两个 NumberPicker 对象实现一个 DialogPreference,它在方向更改后恢复最后更改的 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);
}

有两个问题:

  1. 当我打开我的自定义首选项、更改其中一个选择器的值,然后将手机从纵向旋转到横向时,应用程序崩溃了。错误是 NuLLpointerException,它指向我尝试将恢复的值分配给我的一个 NumberPicker 对象的行。
  2. 这与其说是问题,不如说是问题。我从 Android Developer 主页复制了 BaseSavedState 内部类和 onSaveInstanceState()、onRestoreInstanceState() 函数,但是当我尝试应用程序恢复方向更改时的值时,手机显示的是持久值,而不是方向更改前的最新值。当我试图用日志消息检查代码时,我发现我的手机在 SaveInstanceState isPersisted 检查退出函数并且根本不使用 BaseSavedState 对象。我注释掉了 isPersisted 检查,所以现在我可以从 BaseSavedState 对象保存和检索值,但在那之后问题 nr。 1出现。所以我的问题是,如果偏好是持久的,那么跳过 BaseSavedState 对象创建的原因是什么。我决定跳过持久性检查并强制应用程序创建 BaseSavedState 对象是否是一个错误的决定?

最佳答案

看看这个包含 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>

关于onRestoreInstanceState 中的 Android DialogPreference NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16885542/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com