概述
ContentProvider
作为安卓四大组件之一,它的作用是为不同的应用之间数据共享,提供统一的接口。我们知道安卓系统中应用内部的数据是对外隔离的,要想让其它应用能使用自己的数据(例如通讯录),这个时候就用到了ContentProvider
。
ContentProvider
实际上是对SQLiteOpenHelper
的进一步封装,以一个或多个表的形式将数据呈现给外部应用,通过Uri映射来选择需要操作数据库中的哪个表,并对表中的数据进行增删改查处理。
URI
URI(Uniform Resource Identifier)
即统一资源标识符,是一个用于标识某一互联网资源名称的字符串。下面举个栗子:
上面是一个完整的URI
,其中Host
和Port
一起为Authority
,用于唯一标识一个ContentProvider
,每个部分在安卓中都是可以通过代码获取的,下面这些方法可以获取:
getScheme()
:获取URI
中的Scheme
字符串部分。getHost()
:获取URI
中的Host
部分。getPort()
:获取URI
中的Port
部分。getPath()
:获取URI
中的Path
部分。getQuery()
:获取URI
中的Query
部分。
MIME类型
MIME(Multipurpose Internet Mail Extensions)
即多用途互联网邮件扩展类型,是指定某种扩展名的文件用什么应用程序打开的方式类型。当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
类型/子类型(Content-Type/SubType) | 扩展名 |
---|---|
application/vnd.android.package-archive | .apk |
text/plain | .txt |
image/jpeg | .jpeg |
text/html | .html |
audio/x-pn-realaudio | .rmvb |
audio/mpeg | .mp3 |
video/mp4 | .mp4 |
image/png | .png |
application/json | .json |
application/pdf |
ContentProvider如何共享数据
ContentProvider
通过URI
来标识其他应用要访问的数据,而ContentResolver
通过URI
来定位自己要访问的数据,然后通过ContentResolver
的增、删、改、查方法实现对共享数据的操作。还可以注册ContentObserver
来监听数据是否发生了变化来对应的刷新页面。
UriMatcher类
UriMatcher
类是一个工具类,帮助匹配ContentProvider
中的Uri
。只提供了两个方法–addURI()
和match()
方法。
private final static String AUTHORITY = "com.android.irving.provider";
private final static int STUDENT_URI_CODE = 0;
private final static UriMatcher sUriMatcher;
static {
//初始化,匹配不成功返回NO_MATCH(-1)。
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//添加我们需要匹配的Uri,并把Uri和Uri_Code相关联
sUriMatcher.addURI(AUTHORITY,"student",STUDENT_URI_CODE);
}
//通过match方法能够根据传递的uri匹配到对应的Uri_Code
int uriType = sUriMatcher.match(uri);
ContentUris类
ContentUris
类代码很短,只包含了withAppendedId()
、parseId()
、appendId()
三个静态方法。
调用withAppendedId()
方法会在原始的uri后面添加一个id
(值需要自己指定),调用parseId()
方法可以取出这个id
。
Uri uri = Uri.parse("content://com.android.irving.provider/student");
//向原uri后添加一个值为1的id,得到一个新的uri
Uri withAppendedIdUri = ContentUris.withAppendedId(uri,1);
//取出这个id
long parseId = ContentUris.parseId(withAppendedIdUri);
appendId()
方法用于通过Uri.Builder
方式生成的Uri
使用。
Uri.Builder ub = new Uri.Builder();
//将Uri.Builder创建出来的Uri添加属性
ub.authority("com.android.irving.provider").appendPath("student");
//在Uri后面添加id并得到一个新的Uri
Uri.Builder appendIdUri = ContentUris.appendId(ub,1);
ContentProvider详解
ContentProvider
是一个抽象类,如果我们需要开发自己的内容提供者我们就需要继承这个类并复写其方法,需要实现的主要方法下:
//在创建ContentProvider时调用
public boolean onCreate()
//用于查询指定URI的数据返回一个Cursor
/*
* 第二个参数:告诉Provider要返回的内容(列Column)
* 第三个参数:设置条件,相当于SQL语句中的where。null表示不进行筛选。如果我们只想返回名 * 称为张三的数据,第三个参数应该设置为:“= '张' ”。
* 第四个参数:selectionArgs,这个参数是要配合第三个参数使用的,如果你在第三个参数里面
* 有?,那么你在selectionArgs写的数据就会替换掉 ?
* 第五个参数:sortOrder,按照什么进行排序,相当于SQL语句中的Order by。如果想要结果按照
* ID的降序排列:“DESC”,模式为“ASC”升序排序。
*/
public Cursor query(Uri uri, String[] projection,String selection,String[] selectionArgs, String sortOrder)
//用于向指定URI的ContentProvider中添加数据
public Uri insert()
//用于删除指定URI的数据
public int delete()
//用于更新指定URI的数据
public int update()
//用于返回指定的URI中的数据MIME类型
public String getType()
注意:数据访问的方法insert()
、delete()
和update()
可能被多个线程同时调用,此时必须是线程安全的。
ContentProvider简单使用
- 创建自己的数据列表;
- 自定义类继承
ContentProvider
并实现相关的抽象方法,进行增删改操作后调用getContext().getContentResolver().notifyChange(uri,null)
方法通知ContentObserver
数据发生了变动,以便进行相应的操作。 - 在
AndroidManifest
中声明provider
以及定义相关访问权限;
<!-- student provider 访问权限声明 -->
<permission android:name="com.android.irving.provider.READ_PERMISSION"
android:label="student provider read permission"
android:protectionLevel="normal">
</permission>
<permission android:name="com.android.irving.provider.WRITE_PERMISSION"
android:label="student provider write permission"
android:protectionLevel="normal">
</permission>
<!-- 声明ContentProvider -->
<application>
.......
<provider
android:authorities="com.android.irving.provider"
android:name=".StudentContentProvider"
android:readPermission="com.android.irving.provider.READ_PERMISSION"
android:writePermission="com.android.irving.provider.WRITE_PERMISSION"
android:exported="true">
</provider>
......
</application>
- 通过
ContentResolver
根据URI
进行增删改查操作。
权限声明时protectionLevel设置的是最低风险权限(normal),关于其他等级权限和说明如下:
权限等级 | 说明 |
---|---|
normal | 低风险权限,只要申请了就可以使用,安装时不需要用户确认。 |
dangerous | 高风险权限,安装时需要用户确认授权才可以使用。 |
signature | 只有当申请权限应用与声明此权限应用的数字签名相同时才能将权限授给它。 |
signatureOrSystem | 签名相同或者申请权限的应用为系统应用才能将权限授给它。 |
ContentObserver类
Android
中提供的用来监听ContentProvider
变化的抽象类,可以通过ContentResolver
的registerContentObserver()
和unregisterContentObserver()
方法来注册和注销ContentObserver
监听器。当被监听的ContentProvider
发生变化时,就会回调对应的ContentObserver
的onChange()
方法。
补充
1、UI
线程设置Handler
传入ContentObserver
中,当Uri
中的内容发生变化时,在ContentObserver
的onChange()
方法中通过此Handler
回传数据给UI
线程,通知UI
线程更新数据。
2、在RecyclerView
的Adapter
中提供接口,用于增删改数据时刷新页面。在进行操作的Activity
中发送广播给展示RecyclerView
的Activity
(主展示页面)并携带修改的信息,在主页面接收广播并通过接口提醒RecyclerView
刷新数据。