1190181827806019584 1153952789488054272
内容提供者-向日历中插入提醒事件
0

内容提供者-向日历中插入提醒事件

比如说你要写一个购物,卖票的软件,那么用户可以设置抢票提醒:

20191105_231043.png

使用内容提供者,我们向日历里插入提醒事件,比如说什么时候要抢购商品呀,家人的生日呀,小孩上学,纪念日之类的。

WeChat Image_20191101163433.jpg

今天呢我们也来实现一下这个功能!我们向日历里插入提醒事件。

官方文档地址:

Calendar provider overview

从前面掌握的知识进行思考

如果我们要操作日历的内容提供者,需要什么条件? - 先拿到contentResolver吧,接着要有Uri吧? - 获取URI - 知道各张表的有保存的信息

找到authory

怎么知道它的URI是什么呢?可以看文档,也可以看源码:

android上层应用的源码在这:

android上层应用日历源码

路径如下:

20191104_173449.png

搜索:

static {

20191104_173556.png

也就是说,authorty是:CalendarContract.AUTHORITY

那我们就找这个常量:

同学们如果不下载源码的话,可以在这里搜索

http://androidxref.com/7.1.1_r6/xref/frameworks/base/core/java/android/provider/CalendarContract.java

所以,这个常量是:

    /**
    * This authority is used for writing to or querying from the calendar
    * provider. Note: This is set at first run and cannot be changed without
    * breaking apps that access the provider.
    */
   public static final String AUTHORITY = "com.android.calendar";

那么,咱们的URI,就有了,剩下的,就是看是我们要操作哪张表了。

找到path

20191104_184557.png

以上这些呢,就是对应的表,有什么表请看上面的截图吧!

权限

前面我们有日历内容提供者的源码,我们去看看它注册的地方:

        <provider android:name="CalendarProvider2" android:authorities="com.android.calendar"
                android:label="@string/provider_label"
                android:multiprocess="false"
                android:exported="true"
                android:readPermission="android.permission.READ_CALENDAR"
                android:writePermission="android.permission.WRITE_CALENDAR" />

由上可知道,它需要读写日历的权限

所以我们要在配置文件上添加以下代码

    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />

别急,到这里没完呢。权限我们得考虑6.0以上的版本,也就是api23以上的版本

其实写博客挺麻烦的哈,希望同学们能学到东西吧。

在android api23以年的版本我们需要动态地去获取权限。6.0以下的,声明,安装时会提示用户。

怎么动态获取呢?

就看下面的代码吧,我写一起了,如果不懂的话,后面看视频哈。

package com.sunofbeaches.calendarproviderdemo;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

@RequiresApi(api = Build.VERSION_CODES.M)
public class MainActivity extends AppCompatActivity {

    public static final int PERMISSION_RESULT_CODE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        checkCalendarPermission();
    }

    private void checkCalendarPermission() {
        int writeResult = checkSelfPermission(Manifest.permission.WRITE_CALENDAR);
        int readResult = checkSelfPermission(Manifest.permission.READ_CALENDAR);
        if(writeResult != PackageManager.PERMISSION_GRANTED || readResult != PackageManager.PERMISSION_GRANTED) {
            //没有权限,需要申请权限
            //一般先提示用户,如果用户点击了确定,才去请求权限
            //TODO:同学们就展示一个新的界面,然后如果用户点击不再显示,则不要再显示请求权限了,也不要给用户使用程序,因为没意义呀。
            //TODO:这里我就直接上检查权限的代码,在视频里我们会按实际项目流程走,把提示也做出来。
            //请求权限
            requestPermissions(new String[]{Manifest.permission.WRITE_CALENDAR,Manifest.permission.READ_CALENDAR},PERMISSION_RESULT_CODE);
        } else {
            //有权限
        }
    }


    @Override
    public void onRequestPermissionsResult(int requestCode,@NonNull String[] permissions,@NonNull int[] grantResults) {
        //权限请求结果
        if(requestCode == PERMISSION_RESULT_CODE) {
            // permissions,这个就是前面我们传的数组,请求权限的数组
            // grantResults 结果
            if(grantResults.length == 2 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                //有权限,不用做操作
            } else {
                // 无权限,结束程序
            }
        }
    }
}

表结构

如果没有root的手机我们是不是拿不出表来看呀,那怎么办呢?

authory知道了,表名也知道了,那么我们就随便查询呗,把里面的字段都打出来不就完事了吗?

Uri uri = Uri.parse("content://" + CalendarContract.AUTHORITY + "/calendars");

其实呀,有常量的,所以不需要自己拼接。

 Uri uri = CalendarContract.Calendars.CONTENT_URI;

通过代码获取到表的字段

   //测试表结构
        ContentResolver contentResolver = getContentResolver();
        //Uri uri = Uri.parse("content://" + CalendarContract.AUTHORITY + "/calendars");
        Uri uri = CalendarContract.Calendars.CONTENT_URI;
        Cursor query = contentResolver.query(uri,null,null,null,null);
        String[] columnNames = query.getColumnNames();
        for(String columnName : columnNames) {
            Log.d(TAG,"columnName -- > " + columnName);
        }
        query.close();

运行结果:

columnName -- > account_type
columnName -- > mutators
columnName -- > ownerAccount
columnName -- > allowedReminders
columnName -- > cal_sync3
columnName -- > cal_sync2
columnName -- > COALESCE(isPrimary, ownerAccount = account_name
columnName -- > maxReminders
columnName -- > cal_sync1
columnName -- > cal_sync10
columnName -- > account_name
columnName -- > cal_sync7
columnName -- > cal_sync6
columnName -- > canPartiallyUpdate
columnName -- > cal_sync5
columnName -- > sync_events
columnName -- > cal_sync4
columnName -- > canOrganizerRespond
columnName -- > calendar_color
columnName -- > cal_sync9
columnName -- > calendar_location
columnName -- > cal_sync8
columnName -- > dirty
columnName -- > visible
columnName -- > calendar_timezone
columnName -- > calendar_access_level
columnName -- > allowedAvailability
columnName -- > _sync_id
columnName -- > deleted
columnName -- > name
columnName -- > canModifyTimeZone
columnName -- > _id
columnName -- > calendar_color_index
columnName -- > allowedAttendeeTypes
columnName -- > calendar_displayName

所以,同学们可以通过这种方法研究都有哪些字段

插入事件

插入事件,当我们要做一件事情的时候,可以多问息为什么,怎么样这类问题。

到底怎么写呢?对吧!哪些字段是需要插入内容的呢?

不知道没关系呀,我们手动在手机上添加一条记录,读取出来,不就知道了吗?

插入记录:

TIM图片20191105184104.png

测试代码

        ContentResolver contentResolver = getContentResolver();
        Uri uri = CalendarContract.Events.CONTENT_URI;
        Cursor query = contentResolver.query(uri,null,null,null,null);
        String[] columnNames = query.getColumnNames();
        while(query.moveToNext()) {
            Log.d(TAG,"=============================================");
            for(String columnName : columnNames) {
                Log.d(TAG,"field --- > " + columnName + "value -- > " + query.getString(query.getColumnIndex(columnName)));
            }
            Log.d(TAG,"=============================================");
        }
        query.close();

运行结果

=============================================
field --- > originalAllDayvalue -- > null
field --- > account_typevalue -- > LOCAL
field --- > exrulevalue -- > null
field --- > mutatorsvalue -- > com.android.calendar
field --- > originalInstanceTimevalue -- > null
field --- > allDayvalue -- > 1
field --- > allowedRemindersvalue -- > 0,1
field --- > rrulevalue -- > null
field --- > canOrganizerRespondvalue -- > 1
field --- > lastDatevalue -- > 1573084800000
field --- > visiblevalue -- > 1
field --- > calendar_idvalue -- > 1
field --- > hasExtendedPropertiesvalue -- > 0
field --- > calendar_access_levelvalue -- > 700
field --- > selfAttendeeStatusvalue -- > 0
field --- > allowedAvailabilityvalue -- > 0,1
field --- > eventColor_indexvalue -- > null
field --- > isOrganizervalue -- > 1
field --- > _sync_idvalue -- > null
field --- > calendar_color_indexvalue -- > null
field --- > _idvalue -- > 2
field --- > guestsCanInviteOthersvalue -- > 1
field --- > allowedAttendeeTypesvalue -- > 0,1,2
field --- > dtstartvalue -- > 1572998400000
field --- > guestsCanSeeGuestsvalue -- > 1
field --- > sync_data9value -- > null
field --- > sync_data8value -- > null
field --- > exdatevalue -- > null
field --- > sync_data7value -- > null
field --- > sync_data6value -- > null
field --- > sync_data1value -- > null
field --- > descriptionvalue -- > 记得带上人和设备
field --- > eventTimezonevalue -- > UTC
field --- > availabilityvalue -- > 0
field --- > titlevalue -- > 去红树林拍照
field --- > ownerAccountvalue -- > owner_account_local
field --- > sync_data5value -- > null
field --- > sync_data4value -- > null
field --- > sync_data3value -- > null
field --- > sync_data2value -- > null
field --- > durationvalue -- > null
field --- > lastSyncedvalue -- > 0
field --- > guestsCanModifyvalue -- > 0
field --- > cal_sync3value -- > null
field --- > rdatevalue -- > null
field --- > cal_sync2value -- > null
field --- > maxRemindersvalue -- > 5
field --- > cal_sync1value -- > null
field --- > cal_sync10value -- > null
field --- > account_namevalue -- > account_name_local
field --- > cal_sync7value -- > null
field --- > cal_sync6value -- > null
field --- > cal_sync5value -- > null
field --- > cal_sync4value -- > null
field --- > calendar_colorvalue -- > -30720
field --- > cal_sync9value -- > null
field --- > cal_sync8value -- > null
field --- > dirtyvalue -- > 1
field --- > calendar_timezonevalue -- > null
field --- > accessLevelvalue -- > 0
field --- > eventLocationvalue -- > 红树林深圳湾
field --- > hasAlarmvalue -- > 1
field --- > uid2445value -- > null
field --- > deletedvalue -- > 0
field --- > eventColorvalue -- > null
field --- > organizervalue -- > owner_account_local
field --- > eventStatusvalue -- > 1
field --- > customAppUrivalue -- > null
field --- > canModifyTimeZonevalue -- > 1
field --- > eventEndTimezonevalue -- > null
field --- > customAppPackagevalue -- > null
field --- > original_sync_idvalue -- > null
field --- > hasAttendeeDatavalue -- > 1
field --- > displayColorvalue -- > -30720
field --- > dtendvalue -- > 1573084800000
field --- > original_idvalue -- > null
field --- > sync_data10value -- > null
field --- > calendar_displayNamevalue -- > calendar_displayname_local
=============================================

所以,插入事件我们需要使用到哪些字段呢?

我们看这里:

20191105_184333.png

规则:

  • 您必须加入 CALENDAR_ID 和 DTSTART。
  • 您必须加入 EVENT_TIMEZONE。如需获取系统中已安装时区 ID 的列表,请使用 getAvailableIDs()。请注意,如果您按使Intent 插入事件中所述通过 INSERT Intent 插入事件,则此规则不适用 — 在该情形下,系统会提供默认时区。
  • 对于非重复事件,您必须加入 DTEND。
  • 对于重复事件,您必须加入 DURATION,以及 RRULE 或 RDATE。请注意,如果您按使用 Intent 插入事件中所述通过 INSERT Intent 插入事件,则此规则不适用 — 在该情形下,您可以将 RRULE 与 DTSTART 和 DTEND 结合使用,日历应用会自动将其转换为持续时间。

向日历中插入事件,怎么写呢?

  1. 先通过前面的日历表,查询到日历的id,因为CALENDAR_ID是必须填写的
  2. 必须要填写DTSTART和EVENT_TIMEZONE
  3. 非重复事件,必须加入DTEND
  4. 如果重复事件,则要加入DURATION,RRULE 或 RDATE
        //前面查询出来的
        long calID = 1;
        //时间创建
        Calendar beginTime = Calendar.getInstance();
        //Month value is 0-based. e.g., 0 for January.
        //2019年,12月,7日,8点整
        beginTime.set(2019,11,7,8,00);
        long startMillis = beginTime.getTimeInMillis();
        Calendar endTime = Calendar.getInstance();
        //2019年,12月,7日,8点,45分
        endTime.set(2019,11,7,8,45);
        long endMillis = endTime.getTimeInMillis();
        Log.d(TAG,"beginTime -- > " + startMillis);
        Log.d(TAG,"endTime -- > " + endMillis);
        //准备好插入事件数据库的内容
        ContentResolver cr = getContentResolver();
        ContentValues values = new ContentValues();
        //开始时间
        values.put(CalendarContract.Events.DTSTART,startMillis);
        //结束时间
        values.put(CalendarContract.Events.DTEND,endMillis);
        //标题
        values.put(CalendarContract.Events.TITLE,"去深圳备战坐高铁");
        //描述
        values.put(CalendarContract.Events.DESCRIPTION,"早上八点钟的高铁去陕西");
        //日历ID
        values.put(CalendarContract.Events.CALENDAR_ID,calID);
        //时间时区
        String timeZone = TimeZone.getDefault().getID();
        Log.d(TAG,"time zone -- > " + timeZone);
        values.put(CalendarContract.Events.EVENT_TIMEZONE,timeZone);
        Uri uri = cr.insert(CalendarContract.Events.CONTENT_URI,values);
        Log.d(TAG,"insert result --- > " + uri);

运行结果:

TIM图片20191105222954.png

TIM图片20191105223001.png

事件的更新和删除就不用说了吧,跟普通数据库操作一样。

插入提醒

接下来我们插入提醒内容

以下是提醒表的字段:

20191105_223511.png

规则:插入新提醒时,您必须加入以上所有字段

    //前面我们深圳备战的id,可过查询得到
        long eventID = 3;
        ContentResolver cr = getContentResolver();
        ContentValues values = new ContentValues();
        //15分钟前进行提醒
        values.put(CalendarContract.Reminders.MINUTES,15);
        values.put(CalendarContract.Reminders.EVENT_ID,eventID);
        values.put(CalendarContract.Reminders.METHOD,CalendarContract.Reminders.METHOD_ALERT);
        Uri uri = cr.insert(CalendarContract.Reminders.CONTENT_URI,values);
        Log.d(TAG,"result uri -- > " + uri);

执行结果:

TIM图片20191105223001.png

删除和修改这里就不说了,跟普通数据库操作一样。

其他功能(附录)

这是官方文档的目录

20191105_224813.png

官方文档地址:

日历提供程序

学习中遇到问题就发帖子提问吧!

如果你喜欢作者的文章,欢迎打赏鼓励
评论
发表评论
  • {{item.publishtime|formatDate}}  回复
    {{item.userid}}
    •  回复
      {{item.publishtime|formatDate}}   回复
欢迎关注作者微信公众号
{{subscriptionQrc.subname}}
推荐文章