Context and Calendar
I am using a method to add an event to an internal calendar on the phone. Context has always confused me and this time is no different. The method contract wants the application context. The method call is:
addToCalendar(Context context, String title, long dtstart, long dtend);
This is my code to call the method when a button is pressed:
public class DateAdder extends Activity {
String shiftType;
Date d = new Date();
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button AShift = (Button) findViewById(R.id.AShift);
AShift.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
TextView BtmTxt = (TextView) findViewById(R.id.BtmTxt);
shiftType="A Shift";
addToCalendar(DateAdder.this.getApplicationContext(), shiftType, d.getDate(), d.getDate()+1000);
BtmTxt.setText("Done");
}});
} //END of onCreate
/**
* Adds the event to a calendar. It lets the user choose the calendar
* @param ctx Context ( Please use the application context )
* @param title title of the event
* @param dtstart Start time: The value is the number of milliseconds since Jan. 1, 1970, midnight GMT.
* @param dtend End time: The value is the number of milliseconds since Jan. 1, 1970, midnight GMT.
*/
private static void addToCalendar(Context ctx, final String title, final long dtstart, final long dtend) {
final ContentResolver cr = ctx.getContentResolver();
Cursor cursor ;
if (Integer.parseInt(Build.VERSION.SDK) == 8 )
cursor = cr.query(Uri.parse("content://com.android.calendar/calendars"), new String[]{ "_id", "displayname" }, null, null, null);
else
cursor = cr.query(Uri.parse("content://calendar/calendars"), new String[]{ "_id", "displayname" }, null, null, null);
if ( cursor.moveToFirst() ) {
final String[] calNames = new String[cursor.getCount()];
final int[] calIds = new int[cursor.getCount()];
for (int i = 0; i < calNames.length; i++) {
calIds[i] = cursor.getInt(0);
calNames[i] = cursor.getString(1);
cursor.moveToNext();
}
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setSingleChoiceItems(calNames, -1, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
ContentValues cv = new ContentValues();
cv.put("calendar_id", calIds[which]);
cv.put("title", title);
cv.put("dtstart", dtstart );
cv.put("dtend", dtend);
cv.put("allday", 1);
cv.put("hasAlarm", 0);
Uri newEvent ;
if (Integer.parseInt(Build.VERSION.SDK) == 8 )
newEvent = cr.insert(Uri.parse("content://com.android.calendar/events"), cv);
else
newEvent = cr.insert(Uri.parse("content://com.android.calendar/events"), cv);
if (newEvent != null) {
long id = Long.parseLong( newEvent.getLastPathSegment() );
ContentValues values = new ContentValues();
values.put( "event_id", id );
values.put( "method", 1 );
values.put( "minutes", 15 ); // 15 minuti
if (Integer.parseInt(Build.VERSION.SDK) == 8 开发者_开发百科)
cr.insert( Uri.parse( "content://com.android.calendar/reminders" ), values );
else
cr.insert( Uri.parse( "content://calendar/reminders" ), values );
}
dialog.cancel();
}
});
builder.create().show();
}
cursor.close();
}
}
When I call this from my code I get a force close. The logcat reads:
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
Your problem is that you are creating a Dialog attached to the Application context, which is non-visual. As I see it you don't need the Application context anyway, since all you're doing is accessing the content resolver.
You just need to change this line:
addToCalendar(DateAdder.this.getApplicationContext(),
shiftType, d.getDate(), d.getDate()+1000);
to this:
addToCalendar(DateAdder.this,
shiftType, d.getDate(), d.getDate()+1000);
And the error goes away. (I tested it).
ADDENDUM:
Also change the first line of addToCalendar() to use the application context and thereby fulfill the commented requirement, but I'm unconvinced it makes a difference. I.e.:
final ContentResolver cr = ctx.getApplicationContext().getContentResolver();
change this
addToCalendar(getApplicationContext(), shiftType, d.getDate(), d.getDate()+1000);
to
addToCalendar(---yourClassName---.this.getApplicationContext(), shiftType, d.getDate(), d.getDate()+1000);
an example :
addToCalendar(MainActivity.this.getApplicationContext(), shiftType, d.getDate(), d.getDate()+1000);
If you're inside an activity, you can directly pass this
instead of getApplicationContext
, as Activity extends Context. ApplicationContext is the context for the whole application, whereas passing this
allows you to pass the current context. This may solve your problem.
Sometimes you can also do
(Activity)view.getParent()
Instead of Dateadder.this or dateadder.this.getapplicationContext()
精彩评论