四大组件之一 ContentProvider


前言

本文记录四大组件之一contentprovider学习,从官方文档 .中学习,从创建数据库SQLiteOpenHelper,到利用提供者分享数据,监听内容变化,只记录简单的方法的使用和一些小事例,

ContentProvider的概述

内容提供程序有助于应用管理其自身和其他应用所存储数据的访问,并提供与其他应用共享数据的方法。它们会封装数据,并提供用于定义数据安全性的机制。内容提供程序是一种标准接口,可将一个进程中的数据与另一个进程中运行的代码进行连。最重要的是,通过配置内容提供程序,您可以使其他应用安全地访问和修改您的应用数据。
简而言之:则是提供一个标准接口,给外部应用操作自己应用的数据库。

数据库的创建

  • 继承SQLiteOpenHelper类 创建数据库
    • 构造方法 初始化数据库 (上下文,数据库名,游标卡尺,版本号)cursor用于查询数据的箭头默认指向第一个数据。版本号
    • oncreate方法 创建数据库用的 一般通过sql语句 一般用到的类型是integer和varchar
    • onupdate方法 用于版本升级,当数据库需扩展时,通过sql语句来扩展,最新版本号必须大于等于应用版本号 不然报错
  • 创建Dao类操作数据库
    • 操作数据库需持有SQLiteOpenHelper帮助类,通过帮助类来进行增删改查方法。
    • 增:可以通过sql语句或者api来进行,api ,使用帮助类的insert方法 (表名,null,contentvalues) null表示当插入数据为空所填数值,数据通过contentvalues的键值对方式put该方法成功返回1,错误返回-1
    • 删: 可以通过sql语句或者api来进行,api ,使用帮助类的delete方法 (表名,null,null) 第一个null表示: whereClause条件,第二个null表示whereArgs条件下的值,该方法成功返回删除数据个数,错误返回-1
    • 改:可以通过sql语句或者api来进行,api ,使用帮助类的update方法 (表名,contentvalues,null,null 第一个null表示: whereClause条件,第二个null表示whereArgs条件下的值
    • 查: 可以通过sql语句或者api来进行,api ,使用帮助类的query方法
      (表名,列表数columns,查询那列selection,查询那列的条件值selectionArgs,groupBy,having,orderBy)
  • 创建Bean类 封装数据

ContentProvider 的使用

  • 继承ContentProvider
    • 这里有暴露给外部应用的操作数据库的方法 增删改查方法 getType方法 onCreate方法
    • onCreate方法 创建SQLiteOpenHelper帮助类操作数据库
    • 增删改查方法应用操作帮助类的方法,和Uri ,它是用来匹配外部应用是否使用改数据库的校验。所以需要new UriMatcher(UriMatcher.NO_MATCH)对象 和静态代码块初始化Uri地址(静态的在内存中运行) UriMatcher的addURI方法(校验号,path,校验返回码)校验号返回码。 在增删改查方法,通过外部app传入的url和static代码中校验号/path进行比对放回。
  • 清单文件权限在清单文件中注册provider android:name=继承类 ,android:authorities=静态代码块注册的校验号,android:exported=true
  • 在外部应用中,通过getContentResolver获取ContentResolver对象 来操作数据库

内容观察者

  • 在外部应用中利用ContentResolver对象调用增删改查方法。来操作应用中的数据库。该对象的增删改查方法的参数对应着所写 ContentProvider类中的参数。

  • 在外部应用中利用ContentResolver对象注册内容观察者来监听该数据库中数据变化。registerContentObserver(Uri,true,new ContentObserver(new Handler)) true:表示uri 不管后面是否有path都能返回, 内容观察者是当内容发生改变,你要监听的信息。

日历事件的运用

日历提供者
一键插入事件,通过ContentResolver对象 insert方法
以下是插入新事件的规则:

  • 您必须加入 CALENDAR_ID 和 DTSTART。
  • 您必须加入 EVENT_TIMEZONE。如需获取系统中已安装时区 ID 的列表,请使用 getAvailableIDs()。请注意,如果您按使用 Intent 插入事件中所述通过 INSERT Intent 插入事件,则此规则不适用 — 在该情形下,系统会提供默认时区。
  • 对于非重复事件,您必须加入 DTEND。
  • 对于重复事件,您必须加入 DURATION,以及 RRULE 或 RDATE。请注意,如果您按使用 Intent 插入事件中所述通过 INSERT Intent 插入事件,则此规则不适用 — 在该情形下,您可以将 RRULE 与 DTSTART 和 DTEND 结合使用,日历应用会自动将其转换为持续时间。
  //1:事件表 2.应用weibo相关信息表 3:联系人生日表
        long calID = 1;
        long startMillis = 0;
        long endMillis = 0;
        Calendar beginTime = Calendar.getInstance();
        beginTime.set(2021, 10, 11, 0, 0);
        startMillis = beginTime.getTimeInMillis();
        Calendar endTime = Calendar.getInstance();
        endTime.set(2021, 10, 11, 23, 59);
        endMillis = endTime.getTimeInMillis();

        String timeZone= TimeZone.getDefault().getID();
        Log.d(TAG,timeZone);

        ContentResolver cr = getContentResolver();
        ContentValues eventValues = new ContentValues();
        eventValues.put(CalendarContract.Events.DTSTART, startMillis);
        eventValues.put(CalendarContract.Events.DTEND, endMillis);
        eventValues.put(CalendarContract.Events.TITLE, "双十一购物狂欢节开抢");
        eventValues.put(CalendarContract.Events.DESCRIPTION, "尽情买买买!!");
        eventValues.put(CalendarContract.Events.CALENDAR_ID, calID);
        eventValues.put(CalendarContract.Events.EVENT_TIMEZONE, timeZone);
        Uri resultUri = cr.insert(CalendarContract.Events.CONTENT_URI, eventValues);
        Log.d(TAG,"返回结果"+resultUri);

        String eventID = resultUri.getLastPathSegment();
        Log.d(TAG,eventID);
        ContentValues reminderValues = new ContentValues();
        reminderValues.put(CalendarContract.Reminders.MINUTES, 15);
        reminderValues.put(CalendarContract.Reminders.EVENT_ID, eventID);
        reminderValues.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);
        Uri uri1 = cr.insert(CalendarContract.Reminders.CONTENT_URI, reminderValues);

联系人提供者

ContentResolver cr = getContentResolver();
        Uri rawUri = Uri.parse("content://"+ContactsContract.AUTHORITY+"/raw_contacts");
        Cursor rawCursor = cr.query(rawUri, new String[]{"contact_id","display_name"}, null, null, null);
        String[] columnNames = rawCursor.getColumnNames();

        List<UserInfo> userInfos=new ArrayList<>();
        while (rawCursor.moveToNext()) {
            UserInfo userInfo=new UserInfo();
            userInfo.setId(rawCursor.getString(rawCursor.getColumnIndex("contact_id")));
            userInfo.setDisplayName(rawCursor.getString(rawCursor.getColumnIndex("display_name")));
            userInfos.add(userInfo);
            for (String columnName : columnNames) {
                Log.d(TAG,columnName+" ======= "+rawCursor.getString(rawCursor.getColumnIndex(columnName)));
            }
        }
        rawCursor.close();
        Uri phoneUri = Uri.parse("content://"+ContactsContract.AUTHORITY+"/data/phones");
        for (UserInfo userInfo : userInfos) {
            Cursor phoneCursor = cr.query(phoneUri, new String[]{"data1"}, "raw_contact_id=?", new String[]{userInfo.getId()}, null);
            if (phoneCursor.moveToNext()) {
                userInfo.setPhoneNumber(phoneCursor.getString(0).replace("-",""));
            }
            Log.d(TAG,"userInfo ===>"+userInfo);
            phoneCursor.close();
        }
        /*for (UserInfo userInfo : userInfos) {
            Cursor phoneCursor = cr.query(phoneUri, null, "raw_contact_id=?", new String[]{userInfo.getId()}, null);
            String[] columnNames1 = phoneCursor.getColumnNames();
            while (phoneCursor.moveToNext()) {

                for (String columnName : columnNames1) {
                    Log.d(TAG, columnName + " ======= " + phoneCursor.getString(phoneCursor.getColumnIndex(columnName)));
                }
            }
            phoneCursor.close();
        }*/

这里只能读到手机的联系人手机号,sd卡上无法读取。但能看到联系人的名字,可能得通过另一个数据库去查询。

消息提供者

 ContentResolver contentResolver = getContentResolver();
        Uri uri=Uri.parse("content://sms");
        Cursor cursor = contentResolver.query(uri, null, null, null, null);
        String[] columnNames = cursor.getColumnNames();
        while (cursor.moveToNext()) {
            for (String columnName : columnNames) {
                Log.d(TAG,columnName+" ==== "+cursor.getString(cursor.getColumnIndex(columnName)));
            }
        }
        cursor.close();

通过registerContentObserver 内容观察者来获取消息的实时验证吗

  1. 通过监听sms的数据库变化,获取数据变化的Uri
  2. 通过Uri查询数据库的短信
  3. 对短信进行正则化表达式过滤获取 验证码

获取媒体库提供者形成9宫图返回

  • LoadManager获取数据库信息
    • 如果图片很多时,由于访问数据库耗时操作很多,所以需要在子线程中运行,所以运用LoadManager
    • LoadManager.getInstance()获取LoadManager对象
    • 调用LoadManager的init方法(load_id,args,Callback) 通过Callback的onCreatLoader方法根据load_id,创建返回的Cursor对象,return new CursorLoad(context,uri,projection,selection,selectionArgs,sortOrder);
    • Callback的onLoadFinished方法中得到cursor对象,通过query方法查询需要的信息"_data",“display_name”,“date_added” 并将数据封装到ArrayList当中。
  • 将数据库信息加载到RecyclerView的适配器中
    • 创建RecyclerView(1.找到控件2.设置LayoutManager3.设置Adapter)
    • 将封装好的数据ArrayList对象数据设置Adapter(1.私有化数据2.清空3.重新添加防止数据错乱)
  • 加载布局到RecyclerView当中
    • onCreateViewHolder的创建复用itemView的Holder对象(1.通过获取WindowManager对象 2.itemView设置LayoutParams 3等分)
    • onBindViewHolder绑定数据(数据改变的调用)初始化控件,控件点击事件(imageview,checkbox,view(背景色))
  • 控件点击事件设计
    • imageview的点击
      • 点击一下选择,再点击取消。
      • 创建被选择的ArrayList,根据是否包含被选择,如果选择,点击remove的条目,checkbox的setChecked,setButtonDrawable和view变setVisibility(View.GONE)。如果没选择,则相反。
  • 将选择的数据通过接口返回到Activity中
    • 创建Config,设置回调接口set方法和get方法,回调接口返回选择的图片item对象,设置最大图片数的get和set方法。
    • 防止泄漏设置成单例模式,由于线程无关,设置成饿汉式
    • 在选择图片界面finish的 set回调接口 是否判断接口为空,返回接口
    • 在返回界面get回调接口
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值