简介
内容提供器(Content Provider)主要同于在不同的应用程序之间实现数据共享的一种机制,允许一个程序访问另一个程序中的私有数据,同时可以保证被访问的数据的安全。使用Content Provider我们可以选择只把程序中某一部分数据共享出去,隐私的数据并不向外暴露接口。
假设我们已经向外暴露了共享数据的接口,那么通过什么来访问呢?这里先简单剧透一下,Android中是使用ContentResorver类开启访问的。
另外,因为可以共享出去的数据,可以是文件,也可以是数据库等,而我们开发中一般是使用数据库,所以这里接下来说的ContentProvider的数据就是数据库了。
Uri
那么,问题来了:Android系统中是有很多的ContentProvider的,它们都向外共享着数据,而我们怎么知道我们要访问的ContentProvider的是哪一个呢?
举个例子吧,度娘是一个搜索引擎,谷哥也是一个搜索引擎,那么我们怎么访问并区别它们呢?是的,就是通过ip地址:
度娘ip:www.baidu.com
谷哥ip:www.google.com
OK,现在把谷歌和度娘区分了后,假设我们要使用度娘,要该怎么区分我们要访问的数据是关于”海贼王”,还是关于“银魂”的呢?使用度娘分别搜一下,地址栏中出现如下:
银 魂:www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=银魂 …
海贼王:www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=海贼王 …
正如加粗的部分所示,通过ip后跟着的不同的路径来区分的。
到这里基本上就可以知道怎么访问度娘里海贼王的数据了,但是还得要提一嘴的是,我们还要指明使用什么协议来进行数据的请求,http或者https。那么,一个完整的访问海贼王的URL连接就是:
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=海贼王 …
哎呀,好巧啊~ Android的ContentProvider也采取了类似的机制,这个机制就是使用自定义的内容 URI。
URI为内容提供器中的数据建立了唯一标识符,它主要由两部分组成:
authority:权限或者说地址,类比于ip, 是用于对不同的应用程序(的Content Provider)做区分的,一般为了避免冲突,都会采用程序包名的方式来进行命名,如com.example.app。
path:路径,类比于ip后的“…银魂”,则是用于对同一应用程序(的Content Provider)中不同的数据(如数据库中的数据表)做区分的,通常都会添加到权限的后面。比如某个程序的数据库里存在两张表, table1 和 table2,这时就可以将路径分别命名为/table1和/table2
然后把authority和path进行组合, 那么
访问table1中的数据就可以使用: com.example.app.provider/table1
访问table2中的数据就可以使用:com.example.app.provider/table2同时,内容提供器也是有协议的:content,因此一个访问table1中数据标准的URI的可以写成:content://com.example.app/table1
内容 URI 可以非常清楚地表达出我们想要访问哪个程序中哪张表里的数据有木有!!!
最后根据URI字符串得到Uri对象:
Uri uri = Uri.parse(“content://com.example.app.provider/table1”)
只需要调用 Uri.parse(String uriString)方法即可。
另外,我们还可以在这个内容 URI 的后面加上一个 “id”,如下所示:
content://com.example.app.provider/table1/1
这就可以表示期望访问的是 com.example.app 这个应用的 table1 表中 id 为 1 的数据
当然,这是自定义的,你也可以用其他的方式来这么表示,只不过,这算是规范吧。
内容 URI 的格式主要就只有以上两种,以路径结尾就表示期望访问该表中所有的数据,以 id 结尾就表示期望访问该表中拥有相应 id 的数据。我们可以使用通配符的方式来分别匹配这两种格式的内容 URI,规则如下。
*:表示匹配任意长度的任意字符
#:表示匹配任意长度的数字
所以,一个能够匹配任意表的 URI 就可以写成:
content://com.example.app/*
一个能够匹配 table1 表中任意一行数据 URI 就可以写成:
content://com.example.app/table1/#
ContentProvider 类介绍
首先,ContentProvider是一个抽象的类,那么我们就需要自定义一个类如MyProvider来继承它,并且实现其中的方法(6个抽象方法全部要实现):
package com.yu.contentprovidertest;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.Nullable;
/**
* Created by yu on 2016-04-21.
*/
public class MyProvider extends ContentProvider {
//初始化
@Override
public boolean onCreate() {
return false;
}
//查
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}
//插
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
//删
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
//改
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
// MIME ,其实卵用不大,就是为了告诉ContentResolver你操作的是什么样的数据
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
}
简单介绍一下这六个方法:
onCreate()
初始化内容提供器的时候调用,而且,只有当存在ContentResolver 尝试访问我们程序中的数据时,内容提