安卓四大组件Activity ,Service,BroadCastReceiver,ContentProvider(内容提供者)
1.1内容提供者的作用:
应用程序创建的数据库默认都是私有的,别的应用程序不可以访问里面的数据,如果有需求把自己应用程序私有的数据库暴露给别的用户增删改查,就需要使用内容提供者.
1.2 内容提供者的代码实现
在需要提供给它人数据的应用中
①创建一个项目,并且创建数据库(数据库开启帮助类)(非必要)
②创建一个类,继承ContentProvider内容提供者,
内容提供者,后门程序,提供私有的数据给别的应用程序,默认都是空实现
配置清单文件<provider name=xxx>报错:如果一个tag为provider,必须添加主机名的属性.
Android:authorities=”一般写应用程序的包名”//内线的口令,主机名
在想要获取数据的应用中
①找到后门程序,resolver = getContentResolver()//得到内容提供者的解析器
②定义uri,Uri uri = Uri.parse(“content://”+主机名,前面是固定写法);
ContentValues values = new ContentValues();
③resolver.insert(uri,values);//通过内容解析者,让内容提供者添加一条数据
额外:在继承ContentProvider内容提供者对uri进行解析
主机名是外界都可以知道的(启动时在日志猫中可以看到ActivityThread,pub主机名)
①解析方式通过UriMatcher(uri匹配器)进行解析
Static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
②//采用静态代码块初始化UriMatcher,可以在一开始就判断匹配结果
mUriMatcher.addURI(主机名,暗号名(String),匹配码(int));
③在增删改查的方法里,mUriMatcher.match(uri),返回一个匹配码,可以与在静态代码块中的匹配码进行判断
throw new XXX异常(“异常信息”);
④其它应用程序在指定 uri的时候“content://”+主机名+/暗号(一般写数据库表名)
1.3 内容提供者中代码的一些注意问题
①ContentProvider中想要获取上下文,直接通过getContext()即可//模拟的上下文
②每个方法上对应的
删除的参数 String selection 筛选的条件String[] selectionArgs 执行的参数
添加的参数values,增加的内容
查询的参数 projection(查询的列),selection(where语句)selectionArgs(对应的参数)
sortOrder以什么排序,这个方法返回一个Cursor,不要在查询操作里关闭数据库,否则会提示错误,数据被提前关闭了.
修改的方法:values(修改的值),selection(where条件),selectionArgs(where条件对应的参数)
1.4内容提供者的编写流程
①写一个类继承内容提供者,实现增删改查的方法
②配置清单文件ContentProvider,指定authortites主机属性
③在内容提供者的代码内部,声明UriMatcher匹配规则
④通过uriMatcher坚持uri路径是否正确
⑤在另一个应用程序里,通过ContentProvicer增删改查.
1.5 学习内容提供者的目的
实际开发中,内容提供者很少编写,因为这些数据根本不想让别人看到,而且还进行加密操作,一般只有一些大公司想要打造平台的时候,会对外暴露一部分数据库来给开发者使用.
额外,短信,联系人应用可以通过内容提供者读取
2.利用内容提供者对短信进行增加和删除操作
通过数据库的操作,会在通知栏中显示
2.1短信数据库中,sms表单,type属性,1,是自己发送给别人,2是别人发送给自己
Address 发件人地址, data发送时间,body短信内容
默认权限是对外私有的,但是它是com.android.provider下的程序,是有内容提供者暴露的.
2.2 查看短信的顶层源代码,可以通过清单文件获取主机名”sms”
查看SmsProvider的源代码可以看到具体的匹配规则,如果不加暗号,就是获取所有信息.
额外:需要获取权限READ_SMS WRITE_SMS读写信息
3.通知栏的提醒
界面提醒方式:Toast,对话框,通知栏
通知栏显示的位置是在Systemui进程中(可以看做是进程间的通讯?)
①获取系统服务NotificationManagger nm = getStreamService(NOTIFIACTION_SERVICE);
②nm.notify(id,notification);
Id:通知信息的编号
Notification:通过notification.builder获取,消息栏的类
版本支持的获取是从api16开始的,4.0以上版本才可以使用
③向下兼容的写法:
先获取NotificationManager对象
创建Notification对象 = (图片资源,文本,时间);
//设置通知的点击事件
notification.setLatestEventInfo(context,contentTItle,contentText,contentIntent);
contentTitle 大的标题
contentText 大的文本
contentIntent:PendingIntent:用来描述一个动作和它的意图,这个类是以个延期的意图
实现了Parcelable接口,对象实现了Parcelable才能在进程之间传递
contentIntent = PendingIntent.getActivity(上下文,请求码0即可,intent,flags(为0即可))
//设置通知的声音
Notification.defaults = notification.DEFAULT_SOUND
④//设置打电话的意图
Intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse(tel://110));
//但是没有拨打成功,需要添加权限CALL_PHONE
//设置打开信息的意图
Intent intent = new Intent();
intent.setAction("android.intent.action.MAIN");
intent.addCategory("android.intent.category.DEFAULT");
intent.setType("vnd.android.cursor.dir/mms");
4.联系人的内容提供者
联系人数据库所在的位置: com.android.providers.contacts
4.1联系人数据库的表结构:
打开表的时候会有错误,是因为有一些视图表在外部的工具打开的时候不会刷新,不影响开发.
用到的表有:
①raw_contact表:联系人的ID表
Contact_id列保存联系人的id
②data表:联系人的数据表
Raw_contact_id 表示属于哪个联系人
Data1具体的数据
Mimetype_id代表数据的类型
③mimetype表:联系人数据类型表,对照它可以查询联系人的数据表
要想查询练习人的信息
①查询raw_contact表,获取联系人的Contact_id
②根据contact_id查询Data表,查询联系人的数据
③根据mimetype确定数据的类型
5.1代码实现访问联系人数据库
当主机名用;号分割的时候,contacts;com.androdi,contacts.用前后哪一种都可以.
在系统源码中查找匹配规则,可以查询UriMatcher
需要权限:READ_CONTACTS
cursor记得关闭掉
Mimetype_id这一列在真正查询的时候,查询的不是 data表,而是view_data表,所以在取数据的时候要直接在data表中查memetype,而不是mimetype_id.
在真机上有可能查不出来,因为有的定制机把表的字段名给改了,所以要考虑到机型的适配.
5.2 获取联系人数据的工具方法
①分包:domain(封装联系人数据),utilsbao(实现具体的业务逻辑)
②把联系人从数据库读取出来,封装到集合里即可
5.3 删除联系人的细节问题
删除联系人之后,再查询联系人数据库会报不合法的参数异常
因为安卓有网络,本地保存联系人的保存方式,本地删除了,也会删除网络上的联系人列表.当本地的联系人被删掉了之后,会把联系人的ID保存为null,因为如果这时候网络不好,那么网络保存的联系人信息就没有删掉,所以谷歌就把删除的联系人ID保存为null.等有网同步联系人列表的时候,只需要把为null的信息再网络上删掉即可,而不是把所有联系人跟网络保存的联系人进行一一匹配.
5.4 添加联系人
①获取输入的联系人姓名,电话,邮箱
②获取内容提供者相关信息uri,ContentValues,ContentResolver
③获取raw_contacts表中最大的id
④添加id为最大的id+1,最后再向data表中添加对应的数据即可,
排序_id desc 降序排列
必须指定的列名称有id,mimeType,data1
行结构id data1 mimeType
练习人每一条属性都代表data表中的一行
⑤添加读写联系人的权限
6.内容观察者(高版本的广播接收不到信息,可以通过内容观察者监听)
①可以看做是内容提供者的监听?
②在内容提供者中,通知内容观察者数据发生了变化,为null就是保存下来,不为null就是创建对象立即汇报,实现方式getContext().getContentResolver().notifyChanger(uri,null)
③在需要获知内容观察者的代码中:
注册内容观察者
getContentResolver().regiterContentObserver(uri,notifyForDestor,observer);
第二个参数:需要uri匹配的前面数据(配置清单的路径)满足为true,需要全满足(含匹配规则)为false
第三个参数 new ContentObserver(new xxx里面有一个onChange的方法(需要自己去重写)观察数据变化);
应用场景:需要观察短信的变化,用以备份或还原
7.练习:利用短信内容提供者,开发短信备份与还原的应用