四大组件—BroadcastContentProvider
Posted <天各一方>
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四大组件—BroadcastContentProvider相关的知识,希望对你有一定的参考价值。
文章目录
BroadCast
什么是广播
广播是一种消息型组件,用于在不同组件甚至不同应用之间传递消息。
广播的分类
-
标准广播
完全异步的广播,多个广播接收器可以同时接受广播,且无法被截断。
-
有序广播
有序广播通过sendOrderedBroadcast来发送,所有的广播接收器按照优先级的顺序依次接收,广播的优先级可以通过receiver的intent-filter中android priority属性设置,数值越大优先级越高(-1000~1000)。可以使用abortBroadcast来截断该广播。
-
本地广播
当我们并不需要将广播的内容发送给外部App使用时,仅在自己App内使用就可以使用本地广播。
-
粘性广播
粘性消息的意思就是发送后一直存在于系统消息容器中,等待对应的处理器去处理,当处理完消息后,通过removeStickyBroadcast取消粘性消息。在Android5.0后被废弃。
模型描述
Broadcast是设计模式中的观察者模式:基于消息的发布订阅事件模型
三个角色
- 广播接收者(订阅者)
- 广播发送者(发布者)
- AMS(消息中心)
广播发送者发送广播,通过Binder进程通信机制发送给AMS,请求AMS处理,由AMS在注册列表中寻找合适的广播接收者。广播接收者也是通过Binder机制在AMS中注册。广播接收者通过回调onReceive方法处理消息。
注册方式
静态注册
静态注册,就是在AndroidManifest.xml文件中通过添加标签注册此广播接收者。
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter
android:priority="10">
<action android:name="自定义匹配规则"/>
</intent-filter>
</receiver>
静态注册的广播不会收到任何组件生命周期的影响,即使应用未被打开或者应用关闭后,仍然可以接收到广播。这方便了开发者,但是由于开发者在App中大量的滥用静态广播,导致App从后台被唤醒,严重的影响到手机的电量性能,所以官方在每个都会削减静态广播的功能。在8.0之后,所有的隐式广播不允许使用静态注册的方式来接收(少部分系统广播可用),想要用静态注册的接收者发送广播时需要加上包名。
动态注册
动态注册,即使用Java代码在Activity中注册
broadCastReceiver = new MyBroadCastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("");
registerReceiver(broadCastReceiver,filter);
注意,注册完之后一定要在某个地方接触注册
unregisterReceiver(broadCastReceiver);
ContentProvider
什么是ContenProvider
ContentProvider是一种数据共享型组件,用于向其他组件乃至其他应用程序共享数据。提供一套标准的接口用来获取及操作数据,组件内部实现增删改查四种操作,在内部维持着一份数据集合,这个数据集既可以通过数据库来实现,也可以采用其他任何类型来实现,比如List和Map。
具体使用
设置统一资源标识符(URI)
-
定义:
URI:Uniform Resource Identifier,即统一资源标识符。
-
作用:外界进程通过URI找到对应的ContentProvider和其中的数据,之后进行数据操作。
-
具体使用
Uri uri = Uri.parse("content://com.example.app.provider/table1/1"); // URI模式存在匹配通配符*、# // *:匹配任意长度的任何有效字符的字符串 // 以下的URI表示匹配provider的任何内容 content://com.example.app.provider/* // #:匹配任意长度的数字字符的字符串 // 以下的URI表示匹配provider中的table表的所有行 content://com.example.app.provider/table/#
MIME数据类型
通过重写getType方法将当前Uri对应的MIME类型返回。
一个Uri对应的MIME字符串主要由3个部分组成
- 必须以vnd开头
- 如果内容URI以路径结尾,则后接android.cursor.dir/;如果内容URI以id结尾,则后接android.cursor.item/。
- 最后接上vnd..
ContentProvider
数据组织方式
-
主要以表格的形式组织数据
-
每张表中包含多张表,每个表包含行和列,分别对应记录和字段
同数据库
主要方法
进程间共享数据的本质是对数据进行操作:添加、删除、查询、修改
public class MyContentProvider extends ContentProvider {
public MyContentProvider() {
}
@Override
public boolean onCreate() {
// ContentProvider创建后 或 打开系统后其它进程第一次访问该ContentProvider时 由系统进行调用
// 注:运行在ContentProvider进程的主线程,故不能做耗时操作
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 外部进程 删除 ContentProvider 中的数据
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// 外部进程向 ContentProvider 中添加数据
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// 外部应用 获取 ContentProvider 中的数据
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// 外部进程更新 ContentProvider 中的数据
}
@Override
public String getType(Uri uri) {
// 得到数据类型,即返回当前 Uri 所代表数据的MIME类型
}
}
创建ContentProvider,重写这六个方法。
ContentUris
作用
操作URI
使用
// withAppendedId()作用:向URI追加一个id
Uri uri = Uri.parse("content://com.example.app.provider/user")
Uri resultUri = ContentUris.withAppendedId(uri, 7);
// 最终生成后的Uri为:content://com.example.app.provider/user/7
// parseId()作用:从URL中获取ID
Uri uri = Uri.parse("content://com.example.app.provider/user/7")
long personid = ContentUris.parseId(uri);
//获取的结果为:7
UriMatcher
作用
可以在ContentProvider中根据Uri来匹配对应的数据表
使用
private static final int table1Dir = 0;
private static final int table1Item = 1;
private static final int table2Dir = 2;
private static final int table2Item = 3;
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
uriMatcher.addURI("com.example.app.provider","table1",table1Dir);
uriMatcher.addURI("com.example.app.provider","table1/#",table1Item);
uriMatcher.addURI("com.example.app.provider","table2",table2Dir);
uriMatcher.addURI("com.example.app.provider","table2/#",table2Item);
}
ContentResolver
作用
通过Uri即可操作不同ContentProvider中的数据
外部进程通过ContentResolver类从而与ContentProvider类进行交互
使用
Uri uri = Uri.parse("content://com.example.app.provider/table1");
// 通过getContentResolver
ContentResolver resolver = getContentResolver();
ContentValues values = new ContentValues();
// 增
values.put("id",1);
values.put("name","张三");
resolver.insert(uri,values);
values.clear();
// 删
resolver.delete(uri,"id = ?", new String[]{"1"});
// 改
values.put("id",1);
values.put("name","李四");
resolver.update(uri,values,"id = ?", new String[]{"1"});
values.clear();
// 查
Cursor cursor = resolver.query(uri,null,null,null,null);
while(cursor.moveToNext()){
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
}
cursor.close();
优点
安全
根据ContentProvider工作原理,需要匹配特定的URI才能实现数据的共享,我们并不会向UriMatcher中添加隐私数据的Uri,保护了数据的隐私性。而且,通过ContentProvider来进行数据的增删改查,避免了开放数据库权限而带来的安全问题。
简单高效
通过使用ContentProvider解耦了底层数据的存储方式,无论底层采用何种存储方式,外界对数据访问方式都是统一的。
以上是关于四大组件—BroadcastContentProvider的主要内容,如果未能解决你的问题,请参考以下文章