前言:我们在自己的项目开发中,经常会有预约提醒、定时提醒等方面的需求,这时我们可以使用安卓自己的系统日历来实现。 通过代码向系统日历中写入日历事件、设置提醒,就可以实现到特定时间时提醒用户的功能。
当然了,网上的关于系统日历使用的文章还是挺多的,但是我浏览了一遍,发现没有可以直接拿过来就可以在项目中使用的,所以就有了今天的博客,致力于如果对面的你需要的话就可以直接复制该文章的代码简单快速的实现你的功能。。。
系统日历提醒的大大大的好处是:由于提醒功能是交付给系统日历来做,不会出现应用被杀的情况,会准时提醒需要的事件!!!
总的来说使用系统的日历功能需要做下面的工作:
1.咱们的程序需要有读写日历权限;
2.如果咱们的程序没有日历账户需要先在日历系统创建自己的账户;
3.最后自己实现日历事件的增删改查、提醒功能;
第一步:申请权限
为了实现在项目中可以调用系统日历和插入日程事件,我们首先在AndroidManifest.xml文件中添加相关权限,如下:
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
在这里,既然说到权限自然绕不过去咱们安卓的高版本动态权限校验和请求授权的事情,请看下面;
public void fetchPermission(int requestCode) {
int checkSelfPermission;
try {
checkSelfPermission = ActivityCompat.checkSelfPermission(this,Manifest.permission.WRITE_CALENDAR);
} catch (RuntimeException e) {
e.printStackTrace();
return;
}
// 如果有授权,走正常插入日历逻辑
if (checkSelfPermission == PackageManager.PERMISSION_GRANTED) {
insertCalendar(); // 该方法的实现在文章的后面
return;
} else {
// 如果没有授权,就请求用户授权
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_CALENDAR,
Manifest.permission.READ_CALENDAR}, requestCode);
}
}
下面的代码就是请求的结果回调的处理:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CALENDAR) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户同意的授权请求
insertCalendar();
} else {
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_CALENDAR)) {
// 如果用户不是点击了拒绝就跳转到系统设置页
gotoSettings();
}
}
}
}
这里补充一个小小的知识点:(因为懒的缘故下面内容是复制的某篇文章的内容,表示十分感谢)
为了帮助查找用户可能需要解释的情形,Android 提供了一个实用程序方法,即 shouldShowRequestPermissionRationale()。如果应用之前请求过此权限但用户拒绝了请求,此方法将返回 true。
注:如果用户在过去拒绝了权限请求,并在权限请求系统对话框中选择了 Don’t ask again 选项,此方法将返回 false。如果设备规范禁止应用具有该权限,此方法也会返回 false。
根据测试shouldShowRequestPermissionRationale的返回值主要以下几种情况 :
第一次打开App时 | false |
上次弹出权限点击了禁止(但没有勾选“下次不在询问”) | true |
上次选择禁止并勾选:下次不在询问 | false |
检查并添加日历账户
下面先给出系统calendar content provider相关的uri,以下为Android2.2版本以后的uri,之前的就不写了,至于原因你懂的(哈哈)
private static String CALENDAR_URL = "content://com.android.calendar/calendars";
private static String CALENDAR_EVENT_URL = "content://com.android.calendar/events";
private static String CALENDAR_REMINDER_URL = "content://com.android.calendar/reminders";
/**
* 检查是否已经添加了日历账户,如果没有添加先添加一个日历账户再次进行查询
* 获取账户成功返回账户id,否则返回-1
*/
@Deprecated
private static int checkAndAddCalendarAccount(Context context) {
int oldId = checkCalendarAccount(context);
if (oldId >= 0) {
return oldId;
} else {
long addId = addCalendarAccount(context);
if (addId >= 0) {
return checkCalendarAccount(context);
} else {
return -1;
}
}
}
检查现在是否已经存在日历账户
@Deprecated
private static int checkCalendarAccount(Context context) {
Cursor userCursor = context.getContentResolver().query(Uri.parse(CALENDAR_URL),
null, null, null, null);
try {
if (userCursor == null) { // 查询返回空值
return -1;
}
int count = userCursor.getCount();
if (count > 0) { // 存在现有账户,取第一个账户的id返回
userCursor.moveToFirst();
return userCursor.getInt(userCursor.getColumnIndex(CalendarContract.Calendars._ID));
} else {
return -1;
}
} finally {
if (userCursor != null) {
userCursor.close();
}
}
}
如果没有存在的账户就往系统里面添加一个
private static String CALENDARS_NAME = "meng";
private static String CALENDARS_ACCOUNT_NAME = "meng@test.com";
private static String CALENDARS_ACCOUNT_TYPE = "com.android.meng";
private static String CALENDARS_DISPLAY_NAME = "meng";
@Deprecated
private static long addCalendarAccount(Context context) {
TimeZone timeZone = TimeZone.getDefault();
ContentValues value = new ContentValues();
value.put(CalendarContract.Calendars.NAME, CALENDARS_NAME);
value.put(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME);
value.put(CalendarContract.Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE);
value.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, CALENDARS_DISPLAY_NAME);
value.put(CalendarContract.Calendars.VISIBLE, 1);
value.put(CalendarContract.Calendars.CALENDAR_COLOR, Color.BLUE);
value.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL,
CalendarContract.Calendars.CAL_ACCESS_OWNER);
value.put(CalendarContract.Calendars.SYNC_EVENTS, 1);
value.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, timeZone.getID());
value.put(CalendarContract.Calendars.OWNER_ACCOUNT, CALENDARS_ACCOUNT_NAME);
value.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 0);
Uri calendarUri = Uri.parse(CALENDAR_URL);
calendarUri = calendarUri.buildUpon()
.appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
.appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME,
CALENDARS_ACCOUNT_NAME)
.appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE,
CALENDARS_ACCOUNT_TYPE)
.build();
Uri result = context.getContentResolver().insert(calendarUri, value);
long id = result == null ? -1 : ContentUris.parseId(result);
return id;
}
添加日历事件
public static boolean insertCalendarEvent(Context context, String title, String description,
long beginTimeMillis, long endTimeMillis) {
if (context == null || TextUtils.isEmpty(title) || TextUtils.isEmpty(description)) {
return false;
}
int calId = checkAndAddCalendarAccount(context); // 获取日历账户的id
if (calId < 0) { // 获取账户id失败直接返回,添加日历事件失败
return false;
}
// 如果起始时间为零,使用当前时间
if (beginTimeMillis == 0) {
Calendar beginCalendar = Calendar.getInstance();
beginTimeMillis = beginCalendar.getTimeInMillis();
}
// 如果结束时间为零,使用起始时间+30分钟
if (endTimeMillis == 0) {
endTimeMillis = beginTimeMillis + 30 * 60 * 1000;
}
try {
/** 插入日程 */
ContentValues eventValues = new ContentValues();
eventValues.put(CalendarContract.Events.DTSTART, beginTimeMillis);
eventValues.put(CalendarContract.Events.DTEND, endTimeMillis);
eventValues.put(CalendarContract.Events.TITLE, title);
eventValues.put(CalendarContract.Events.DESCRIPTION, description);
eventValues.put(CalendarContract.Events.CALENDAR_ID, 1);
eventValues.put(CalendarContract.Events.EVENT_LOCATION, "蒙app");
TimeZone tz = TimeZone.getDefault(); // 获取默认时区
eventValues.put(CalendarContract.Events.EVENT_TIMEZONE, tz.getID());
Uri eUri = context.getContentResolver().insert(Uri.parse(CALENDAR_EVENT_URL), eventValues);
long eventId = ContentUris.parseId(eUri);
if (eventId == 0) { // 插入失败
return false;
}
/** 插入提醒 - 依赖插入日程成功 */
ContentValues reminderValues = new ContentValues();
// uri.getLastPathSegment();
reminderValues.put(CalendarContract.Reminders.EVENT_ID, eventId);
reminderValues.put(CalendarContract.Reminders.MINUTES, 10); // 提前10分钟提醒
reminderValues.put(CalendarContract.Reminders.METHOD,
CalendarContract.Reminders.METHOD_ALERT);
Uri rUri = context.getContentResolver().insert(Uri.parse(CALENDAR_REMINDER_URL),
reminderValues);
if (rUri == null || ContentUris.parseId(rUri) == 0) {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
删除事件
@Deprecated
public static void deleteCalendarEvent(Context context, String title) {
if (context == null) {
return;
}
Cursor eventCursor = context.getContentResolver().query(Uri.parse(CALENDAR_EVENT_URL),
null, null, null, null);
try {
if (eventCursor == null) { // 查询返回空值
return;
}
if (eventCursor.getCount() > 0) {
// 遍历所有事件,找到title跟需要查询的title一样的项
for (eventCursor.moveToFirst(); !eventCursor.isAfterLast(); eventCursor.moveToNext()) {
String eventTitle = eventCursor.getString(eventCursor.getColumnIndex("title"));
if (!TextUtils.isEmpty(title) && title.equals(eventTitle)) {
int id = eventCursor.getInt(eventCursor
.getColumnIndex(CalendarContract.Calendars._ID)); // 取得id
Uri deleteUri = ContentUris.withAppendedId(Uri.parse(CALENDAR_EVENT_URL), id);
int rows = context.getContentResolver().delete(deleteUri, null, null);
if (rows == -1) { // 事件删除失败
return;
}
}
}
}
} finally {
if (eventCursor != null) {
eventCursor.close();
}
}
}
好了,到此结束了,如果你需要,上面的代码你直接copy进你的项目就可以使用了,非常简单的!!!
see you