调用 DatePickerDialog Show 时无法添加 Window 异常
Unable to Add Window Exception on calling DatePickerDialog Show
我是 Android Studio 和 Android 开发的新手,但通过一些在线查询,我必须编写一个 class 来处理 DatePickerDialog 和 TimePickerDialog 请求以设置日期.
基于我写的例子 class:
class DatePick
{
protected android.app.Activity activity;
public final java.util.Calendar currentDate = java.util.Calendar.getInstance();
private boolean picked;
public java.util.Calendar date;
public java.util.Calendar pickDate()
{
this.picked = false;
this.date = java.util.Calendar.getInstance();
android.app.DatePickerDialog datePicker = new android.app.DatePickerDialog(this.activity.getApplicationContext(), new android.app.DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(android.widget.DatePicker view, int year, int month, int dayOfMonth) { cweb.companion.DatePick.this.date.set(view.getYear(), view.getMonth(), view.getDayOfMonth()); } }, this.currentDate.get(java.util.Calendar.YEAR), this.currentDate.get(java.util.Calendar.MONTH), this.currentDate.get(java.util.Calendar.DAY_OF_MONTH)) { @Override public void onClick(android.content.DialogInterface dialog, int which) { cweb.companion.DatePick.this.picked = (which == android.content.DialogInterface.BUTTON_POSITIVE); } };
datePicker.show(); //todo resolve: exception here for unable to add window null token
datePicker = null; //dispose?
if (this.picked)
{
android.app.TimePickerDialog timePicker = new android.app.TimePickerDialog(this.activity.getApplicationContext(), new android.app.TimePickerDialog.OnTimeSetListener() { @Override public void onTimeSet(android.widget.TimePicker view, int hourOfDay, int minute) { cweb.companion.DatePick.this.date.set(cweb.companion.DatePick.this.date.get(java.util.Calendar.YEAR), cweb.companion.DatePick.this.date.get(java.util.Calendar.MONTH), cweb.companion.DatePick.this.date.get(java.util.Calendar.DAY_OF_MONTH), hourOfDay, minute); } }, this.currentDate.get(java.util.Calendar.HOUR_OF_DAY), this.currentDate.get(java.util.Calendar.MINUTE), true) { @Override public void onClick(android.content.DialogInterface dialog, int which) { cweb.companion.DatePick.this.picked = (which == android.content.DialogInterface.BUTTON_POSITIVE); } };
timePicker.show(); //picked may change back to false after that (maybe, depending on the user's confirm/abort)
timePicker = null; //dispose?
}
if (!this.picked) { this.date = null; }
return cweb.companion.DatePick.this.date;
}
public static java.lang.String toString(java.util.Calendar date) { return java.lang.String.format("%02d", date.get(java.util.Calendar.DAY_OF_MONTH)) + "/" + java.lang.String.format("%02d", date.get(java.util.Calendar.MONTH)) + "/" + java.lang.String.format("%04d", date.get(java.util.Calendar.YEAR)) + " " + java.lang.String.format("%02d", date.get(java.util.Calendar.HOUR_OF_DAY)) + ":" + java.lang.String.format("%02d", date.get(java.util.Calendar.MINUTE)) + ":" + java.lang.String.format("%02d", date.get(java.util.Calendar.SECOND)); }
public DatePick(android.app.Activity activity) { this.activity = activity; }
}
然后通过以下声明在我的 MainActivity(应用程序中唯一的 activity)中调用它:
public class MainActivity extends androidx.appcompat.app.AppCompatActivity
{
protected android.widget.Button datePickCall;
private java.util.Calendar date;
private void pickdatePickCall()
{
cweb.companion.DatePick picker = new cweb.companion.DatePick(this);
this.date = picker.pickDate();
this.datePickCall.setText(cweb.companion.DatePick.toString(this.date));
}
@Override protected void onCreate(android.os.Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setContentView(cweb.companion.R.layout.activity_main);
this.datePickCall = this.findViewById(cweb.companion.R.id.datePickCall);
this.datePickCall.setOnClickListener(new android.view.View.OnClickListener() { @Override public void onClick(android.view.View v) { cweb.companion.MainActivity.this.pickdatePickCall(); }});
}
}
但是当我调试应用程序时,在 DatePick class 处标有待办事项的行上,它调用了对话框的 "show()" 方法,我得到一个异常:
Unable to add window - Token null, is activity running?
似乎无法理解它为什么不起作用,有什么帮助吗?
尝试用 activity 上下文替换应用程序上下文。
DatePickerDialog(Context context) Creates a new date picker dialog for the current date using the parent context's default date picker dialog theme.
来源:
https://developer.android.com/reference/android/app/DatePickerDialog
更新:
我知道这看起来很矛盾。可以假设应用程序上下文拥有 activity 拥有的一切,甚至更多。但事实并非如此。 getApplicationContext() 不能用于启动对话框。 More here.
对于您的代码:当您编写 new cweb.companion.DatePick(this);
时,您已经传递了 activity 上下文,因此您可以去掉 getApplicationContext()
并编写 new DatePickerDialog(activity, new ...
我还注意到您总是在不必要的时候使用 this.
。例如我会更换
this.picked = false;
与 picked = false;
并且您可以使用导入来摆脱那些长包名称。我会替换
之类的东西
android.app.DatePickerDialog datePicker = new android.app.DatePickerDialog(...
和
import android.app.DatePickerDialog;
public class DatePick { ...
DatePickerDialog datePicker = new DatePickerDialog(...
只是为了更容易阅读代码。
尝试一下,希望对您有所帮助。
更新二:
以下代码在我的电脑上运行。它显示了对话框,然后是祝酒词。尝试使其适应您的需要。如果这对您不起作用,那么我不知道原因。 ;)
package com.something.dialogtest;
import android.app.DatePickerDialog;
import android.os.Bundle;
import android.widget.DatePicker;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Calendar;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DatePickerDialog datePicker = new DatePickerDialog(this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
Toast.makeText(MainActivity.this, "onDateSet", Toast.LENGTH_SHORT).show();
}
},
Calendar.getInstance().get(Calendar.YEAR),
Calendar.getInstance().get(Calendar.MONTH),
Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
datePicker.show();
}
}
我是 Android Studio 和 Android 开发的新手,但通过一些在线查询,我必须编写一个 class 来处理 DatePickerDialog 和 TimePickerDialog 请求以设置日期.
基于我写的例子 class:
class DatePick
{
protected android.app.Activity activity;
public final java.util.Calendar currentDate = java.util.Calendar.getInstance();
private boolean picked;
public java.util.Calendar date;
public java.util.Calendar pickDate()
{
this.picked = false;
this.date = java.util.Calendar.getInstance();
android.app.DatePickerDialog datePicker = new android.app.DatePickerDialog(this.activity.getApplicationContext(), new android.app.DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(android.widget.DatePicker view, int year, int month, int dayOfMonth) { cweb.companion.DatePick.this.date.set(view.getYear(), view.getMonth(), view.getDayOfMonth()); } }, this.currentDate.get(java.util.Calendar.YEAR), this.currentDate.get(java.util.Calendar.MONTH), this.currentDate.get(java.util.Calendar.DAY_OF_MONTH)) { @Override public void onClick(android.content.DialogInterface dialog, int which) { cweb.companion.DatePick.this.picked = (which == android.content.DialogInterface.BUTTON_POSITIVE); } };
datePicker.show(); //todo resolve: exception here for unable to add window null token
datePicker = null; //dispose?
if (this.picked)
{
android.app.TimePickerDialog timePicker = new android.app.TimePickerDialog(this.activity.getApplicationContext(), new android.app.TimePickerDialog.OnTimeSetListener() { @Override public void onTimeSet(android.widget.TimePicker view, int hourOfDay, int minute) { cweb.companion.DatePick.this.date.set(cweb.companion.DatePick.this.date.get(java.util.Calendar.YEAR), cweb.companion.DatePick.this.date.get(java.util.Calendar.MONTH), cweb.companion.DatePick.this.date.get(java.util.Calendar.DAY_OF_MONTH), hourOfDay, minute); } }, this.currentDate.get(java.util.Calendar.HOUR_OF_DAY), this.currentDate.get(java.util.Calendar.MINUTE), true) { @Override public void onClick(android.content.DialogInterface dialog, int which) { cweb.companion.DatePick.this.picked = (which == android.content.DialogInterface.BUTTON_POSITIVE); } };
timePicker.show(); //picked may change back to false after that (maybe, depending on the user's confirm/abort)
timePicker = null; //dispose?
}
if (!this.picked) { this.date = null; }
return cweb.companion.DatePick.this.date;
}
public static java.lang.String toString(java.util.Calendar date) { return java.lang.String.format("%02d", date.get(java.util.Calendar.DAY_OF_MONTH)) + "/" + java.lang.String.format("%02d", date.get(java.util.Calendar.MONTH)) + "/" + java.lang.String.format("%04d", date.get(java.util.Calendar.YEAR)) + " " + java.lang.String.format("%02d", date.get(java.util.Calendar.HOUR_OF_DAY)) + ":" + java.lang.String.format("%02d", date.get(java.util.Calendar.MINUTE)) + ":" + java.lang.String.format("%02d", date.get(java.util.Calendar.SECOND)); }
public DatePick(android.app.Activity activity) { this.activity = activity; }
}
然后通过以下声明在我的 MainActivity(应用程序中唯一的 activity)中调用它:
public class MainActivity extends androidx.appcompat.app.AppCompatActivity
{
protected android.widget.Button datePickCall;
private java.util.Calendar date;
private void pickdatePickCall()
{
cweb.companion.DatePick picker = new cweb.companion.DatePick(this);
this.date = picker.pickDate();
this.datePickCall.setText(cweb.companion.DatePick.toString(this.date));
}
@Override protected void onCreate(android.os.Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setContentView(cweb.companion.R.layout.activity_main);
this.datePickCall = this.findViewById(cweb.companion.R.id.datePickCall);
this.datePickCall.setOnClickListener(new android.view.View.OnClickListener() { @Override public void onClick(android.view.View v) { cweb.companion.MainActivity.this.pickdatePickCall(); }});
}
}
但是当我调试应用程序时,在 DatePick class 处标有待办事项的行上,它调用了对话框的 "show()" 方法,我得到一个异常:
Unable to add window - Token null, is activity running?
似乎无法理解它为什么不起作用,有什么帮助吗?
尝试用 activity 上下文替换应用程序上下文。
DatePickerDialog(Context context) Creates a new date picker dialog for the current date using the parent context's default date picker dialog theme.
来源: https://developer.android.com/reference/android/app/DatePickerDialog
更新: 我知道这看起来很矛盾。可以假设应用程序上下文拥有 activity 拥有的一切,甚至更多。但事实并非如此。 getApplicationContext() 不能用于启动对话框。 More here.
对于您的代码:当您编写 new cweb.companion.DatePick(this);
时,您已经传递了 activity 上下文,因此您可以去掉 getApplicationContext()
并编写 new DatePickerDialog(activity, new ...
我还注意到您总是在不必要的时候使用 this.
。例如我会更换
this.picked = false;
与 picked = false;
并且您可以使用导入来摆脱那些长包名称。我会替换
之类的东西android.app.DatePickerDialog datePicker = new android.app.DatePickerDialog(...
和
import android.app.DatePickerDialog;
public class DatePick { ...
DatePickerDialog datePicker = new DatePickerDialog(...
只是为了更容易阅读代码。 尝试一下,希望对您有所帮助。
更新二: 以下代码在我的电脑上运行。它显示了对话框,然后是祝酒词。尝试使其适应您的需要。如果这对您不起作用,那么我不知道原因。 ;)
package com.something.dialogtest;
import android.app.DatePickerDialog;
import android.os.Bundle;
import android.widget.DatePicker;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Calendar;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DatePickerDialog datePicker = new DatePickerDialog(this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
Toast.makeText(MainActivity.this, "onDateSet", Toast.LENGTH_SHORT).show();
}
},
Calendar.getInstance().get(Calendar.YEAR),
Calendar.getInstance().get(Calendar.MONTH),
Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
datePicker.show();
}
}