多个DatePicker,屏幕旋转时强制关闭
这是我的第一个 Android 应用程序,在此之前我根本没有 Java 知识。
我使用了以下代码(在另一个问题中找到,作者:Adam L.),我有 28 个时间选择器,在稍微改变代码后效果很好。
但我注意到的一件事是,当我处于 timepickerdialog (或使用此处显示的代码时的 datepickerdialog )时,我会强制关闭(空指针异常)并更改屏幕方向。
我想我需要使用 onDestroy 保存一些信息并使用 onStart 再次恢复它,但我不知道如何完成此操作。
在我自己的代码中,我使用 timepickerdialogs 但 Adam L. 的代码更干净,因此解决那里的问题也可以解决我的问题自己的问题。
import java.util.Calendar;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TextView;
public class MultiDatePickerActivity extends Activity {
private TextView startDateDisplay;
private TextView endDateDisplay;
private Button startPickDate;
private Button endPickDate;
private Calendar startDate;
private Calendar endDate;
static final int DATE_DIALOG_ID = 0;
private TextView activeDateDisplay;
private Calendar activeDate;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.multidatepicker);
/* capture our View elements for the start date function */
startDateDisplay = (TextView) findViewById(R.id.startDateDisplay);
startPickDate = (Button) findViewById(R.id.startPickDate);
/* get the current date */
startDate = Calendar.getInstance();
/* add a click listener to the button */
startPickDate.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showDateDialog(startDateDisplay, startDate);
}
});
/* capture our View elements for the end date function */
endDateDisplay = (TextView) findViewById(R.id.endDateDisplay);
endPickDate = (Button) findViewById(R.id.endPickDate);
/* get the current date */
endDate = Calendar.getInstance();
/* add a click listener to the button */
endPickDate.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showDateDialog(endDateDisplay, endDate);
}
});
/* display the current date (this method is below) */
updateDisplay(startDateDisplay, startDate);
updateDisplay(endDateDisplay, endDate);
}
private void updateDisplay(TextView dateDisplay, Calendar date) {
dateDisplay.setText(
new StringBuilder()
// Month is 0 based so add 1
.append(date.get(Calendar.MONTH) + 1).append("-")
.append(date.get(Calendar.DAY_OF_MONTH)).append("-")
.append(date.get(Calendar.YEAR)).append(" "));
}
public void showDateDialog(TextView dateDisplay, Calendar date) {
activeDateDisplay = dateDisplay;
activeDate = date;
showDialog(DATE_DIALOG_ID);
}
private OnDateSetListener dateSetListener = new OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
activeDate.set(Calendar.YEAR, year);
activeDate.set(Calendar.MONTH, monthOfYear);
activeDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
updateDisplay(activeDateDisplay, activeDate);
unregisterDateDisplay();
}
};
private void unregisterDateDisplay() {
activeDateDisplay = null;
activeDate = null;
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DATE_DIALOG_ID:
return new DatePickerDialog(this, dateSetListener, activeDate.get(Calendar.YEAR), activeDate.get(Calendar.MONTH), activeDate.get(Calendar.DAY_OF_MONTH));
}
return null;
}
@Override
protected void onPrepareDialog(int id, Dialog dialog) {
super.onPrepareDialog(id, dialog);
switch (id) {
case DATE_DIALOG_ID:
((DatePickerDialog) dialog).updateDate(activeDate.get(Calendar.YEAR), activeDate.get(Calendar.MONTH), activeDate.get(Calendar.DAY_OF_MONTH));
break;
}
}
}
我认为这是 Eclipse 中 logcat 有趣的部分:
12-18 11:32:52.415: INFO/ActivityManager(577): Displayed activity se.bergsland.manydatepickers/.ManyDatePickers: 993 ms
12-18 11:32:57.625: DEBUG/dalvikvm(1734): GC freed 1950 objects / 104136 bytes in 192ms
12-18 11:33:00.396: INFO/WindowManager(577): Config changed: { scale=1.0 imsi=0/0 locale=en_US touch=3 key=2/1/2 nav=3 orien=2 }
12-18 11:33:00.535: DEBUG/StatusBar(577): updateResources
12-18 11:33:00.595: DEBUG/AndroidRuntime(1763): Shutting down VM
12-18 11:33:00.595: WARN/dalvikvm(1763): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)
12-18 11:33:00.605: ERROR/AndroidRuntime(1763): Uncaught handler: thread main exiting due to uncaught exception
12-18 11:33:00.615: INFO/WindowManager(577): onOrientationChanged, rotation changed to 0
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): java.lang.RuntimeException: Unable to start activity ComponentInfo{se.bergsland.manydatepickers/se.bergsland.manydatepickers.ManyDatePickers}: java.lang.NullPointerException
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2268)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3278)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.access$1900(ActivityThread.java:112)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.os.Handler.dispatchMessage(Handler.java:99)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.os.Looper.loop(Looper.java:123)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.main(ActivityThread.java:3948)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at java.lang.reflect.Method.invokeNative(Native Method)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at java.lang.reflect.Method.invoke(Method.java:521)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at dalvik.system.NativeStart.main(Native Method)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): Caused by: java.lang.NullPointerException
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at se.bergsland.manydatepickers.ManyDatePickers.onCreateDialog(ManyDatePickers.java:102)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.Activity.restoreManagedDialogs(Activity.java:857)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.Activity.performRestoreInstanceState(Activity.java:801)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1172)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2245)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): ... 12 more
This is my first Android-app and prior to this I had no Java knowledge at all.
I used the following code (found in another question, by Adam L.), I have 28 timepickers and it worked great after altering the code a bit.
But one thing I notice is that I get force close (nullpointerexception) when I am in a timepickerdialog (or datepickerdialog when using the code as it is displayed here) and change orientation of the screen.
I guess I need to save some info with onDestroy and restoring it again with onStart but I do not know how to accomplish this.
In my own code I use timepickerdialogs but Adam L.s code is cleaner so solving the problem there would also solve my own problem.
import java.util.Calendar;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TextView;
public class MultiDatePickerActivity extends Activity {
private TextView startDateDisplay;
private TextView endDateDisplay;
private Button startPickDate;
private Button endPickDate;
private Calendar startDate;
private Calendar endDate;
static final int DATE_DIALOG_ID = 0;
private TextView activeDateDisplay;
private Calendar activeDate;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.multidatepicker);
/* capture our View elements for the start date function */
startDateDisplay = (TextView) findViewById(R.id.startDateDisplay);
startPickDate = (Button) findViewById(R.id.startPickDate);
/* get the current date */
startDate = Calendar.getInstance();
/* add a click listener to the button */
startPickDate.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showDateDialog(startDateDisplay, startDate);
}
});
/* capture our View elements for the end date function */
endDateDisplay = (TextView) findViewById(R.id.endDateDisplay);
endPickDate = (Button) findViewById(R.id.endPickDate);
/* get the current date */
endDate = Calendar.getInstance();
/* add a click listener to the button */
endPickDate.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showDateDialog(endDateDisplay, endDate);
}
});
/* display the current date (this method is below) */
updateDisplay(startDateDisplay, startDate);
updateDisplay(endDateDisplay, endDate);
}
private void updateDisplay(TextView dateDisplay, Calendar date) {
dateDisplay.setText(
new StringBuilder()
// Month is 0 based so add 1
.append(date.get(Calendar.MONTH) + 1).append("-")
.append(date.get(Calendar.DAY_OF_MONTH)).append("-")
.append(date.get(Calendar.YEAR)).append(" "));
}
public void showDateDialog(TextView dateDisplay, Calendar date) {
activeDateDisplay = dateDisplay;
activeDate = date;
showDialog(DATE_DIALOG_ID);
}
private OnDateSetListener dateSetListener = new OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
activeDate.set(Calendar.YEAR, year);
activeDate.set(Calendar.MONTH, monthOfYear);
activeDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
updateDisplay(activeDateDisplay, activeDate);
unregisterDateDisplay();
}
};
private void unregisterDateDisplay() {
activeDateDisplay = null;
activeDate = null;
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DATE_DIALOG_ID:
return new DatePickerDialog(this, dateSetListener, activeDate.get(Calendar.YEAR), activeDate.get(Calendar.MONTH), activeDate.get(Calendar.DAY_OF_MONTH));
}
return null;
}
@Override
protected void onPrepareDialog(int id, Dialog dialog) {
super.onPrepareDialog(id, dialog);
switch (id) {
case DATE_DIALOG_ID:
((DatePickerDialog) dialog).updateDate(activeDate.get(Calendar.YEAR), activeDate.get(Calendar.MONTH), activeDate.get(Calendar.DAY_OF_MONTH));
break;
}
}
}
I think this is the interesting part of the logcat in Eclipse:
12-18 11:32:52.415: INFO/ActivityManager(577): Displayed activity se.bergsland.manydatepickers/.ManyDatePickers: 993 ms
12-18 11:32:57.625: DEBUG/dalvikvm(1734): GC freed 1950 objects / 104136 bytes in 192ms
12-18 11:33:00.396: INFO/WindowManager(577): Config changed: { scale=1.0 imsi=0/0 locale=en_US touch=3 key=2/1/2 nav=3 orien=2 }
12-18 11:33:00.535: DEBUG/StatusBar(577): updateResources
12-18 11:33:00.595: DEBUG/AndroidRuntime(1763): Shutting down VM
12-18 11:33:00.595: WARN/dalvikvm(1763): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)
12-18 11:33:00.605: ERROR/AndroidRuntime(1763): Uncaught handler: thread main exiting due to uncaught exception
12-18 11:33:00.615: INFO/WindowManager(577): onOrientationChanged, rotation changed to 0
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): java.lang.RuntimeException: Unable to start activity ComponentInfo{se.bergsland.manydatepickers/se.bergsland.manydatepickers.ManyDatePickers}: java.lang.NullPointerException
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2268)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3278)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.access$1900(ActivityThread.java:112)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.os.Handler.dispatchMessage(Handler.java:99)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.os.Looper.loop(Looper.java:123)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.main(ActivityThread.java:3948)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at java.lang.reflect.Method.invokeNative(Native Method)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at java.lang.reflect.Method.invoke(Method.java:521)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at dalvik.system.NativeStart.main(Native Method)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): Caused by: java.lang.NullPointerException
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at se.bergsland.manydatepickers.ManyDatePickers.onCreateDialog(ManyDatePickers.java:102)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.Activity.restoreManagedDialogs(Activity.java:857)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.Activity.performRestoreInstanceState(Activity.java:801)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1172)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2245)
12-18 11:33:00.625: ERROR/AndroidRuntime(1763): ... 12 more
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在您的活动中使用此代码:
在您的清单文件中使用此代码:
Use this code in your Activity:
Use this in your manifest file:
恐怕法加斯的建议并不是最好的。您的问题是,在配置更改后调用
onCreateDialog()
时,activateDate
为 null。因为您只在onClick()
中设置了一次。您需要在onStart()
中设置它。在onResume()
中设置它不起作用,但您可能还需要在那里设置它,请参阅我的问题Android生命周期:在onStart()或onResume()中的activity中填充数据?。如果您想在显示对话框的那一刻更新日期,那么您可以通过
updateDate()
直接执行Calendar.getInstance()
>onPrepareDialog()。Fargath 解决方案的问题在于您隐藏了软键盘,但问题仍然存在于具有硬件键盘的设备(例如 G1)上。来电也是如此。我不确定 onConfigurationChanged() 与它有什么关系。
Fargath's advice wasn't the best I'm afraid. Your problem is that
activateDate
is null whenonCreateDialog()
is called after a configuration change. Since you only set it once inonClick()
. You need to set it inonStart()
. Setting it inonResume()
won't work, but you might need to set it there as well, see my problem Android lifecycle: Fill in data in activity in onStart() or onResume()?.If you want to update the dates at the exact moment that the dialog is being shown, then you can do a direct
Calendar.getInstance()
viaupdateDate()
inonPrepareDialog()
.The problem with Fargath's solution is that you are hiding the soft keyboard, but the problem still exists on devices with a hardware keyboard such as the G1. The same goes for incoming phone calls. I'm not sure what
onConfigurationChanged()
has to do with it.