一、概述
Content Provider相当于是程序与程序之间的接口。让原本不可能通信的程序,通过内容提供者这个桥梁变得可以通信。
应用程序默认创建的数据库文件只有自己才能访问,其他的应用程序是不具备读写权限的。
把自己应用程序的数据库文件(内容)暴露出来,给其他应用程序访问。 与AIDL不太一样,内容提供者暴露的是磁盘中的数据, aidl暴露的是内存中的数据。
二、使用条件
一般来说,我们只使用Android系统的内容提供者,但是不会写。因为目前的趋势是:没有人会把自己的数据公布出去(腾讯也不会)。即使,搞一个provider,也不一定会有人去用。
一般情况下,都是系统暴露数据给第三方程序访问,很少有或者是几乎没有第三方程序暴露数据给其他的程序访问。
开发的时候,更多的情况,写的都是访问内容提供者的代码,一般都是访问系统应用程序暴露出来的数据
联系人应用 、短信应用 、 多媒体库
三、内容提供者的使用步骤
- 定义一个类 ,继承 contentProvider
public class BackDoor extends ContentProvider {}
注册contentprovider , 要添加authorities的属性
<!-- 1.注册内容提供者 ,一定要声明authorities , 这个authorities 相当于是口令,来访的人必须要说出这个口令,否则内容提供者将不受理,不帮它干活。 2.要4.3以上版本,一定要加上exporeted=true; --> <provider android:name="com.sky.db.DbProvider" android:exported="true" android:authorities="com.sky.db.BANK"> </provider>
声明 URIMatcher ( uri 匹配器)
/** * 只要谁能说对了这个口令就可以来操作内容提供者,这样实际上是不安全的,所以为了防范或者是过滤 必须要对uri进行严格的匹配,或者是叫做升级口令 * ,密码 */ // 声明一个匹配器,只要来调用crud的方法,都先用这个匹配器去过滤uri , 里面给定的参数是指:如果没有匹配,那么将返回这个code static UriMatcher match = new UriMatcher(UriMatcher.NO_MATCH);
使用静态代码块,预设匹配规则
// 使用静态的代码块来预设一些匹配规则,也就是给这个匹配器先制订一套规则 static { // 在这里已经预设了一个匹配规则 来访的uri,必须是这样才能通过 // content://xiaojidunmogu/huangheruhai // 来访必须匹配主机名 , path , 如果匹配,将返回1 , 否则将返回 -1 // match.addURI("com.sky.db.BANK", "bank", 1); /* * 一般,如果要暴露多张数据表,这里必须要指定多条过滤规则 , 一般这个path都不写无意义的单词,多数情况下 *写的是表的名字,因为这样写,外部程序可以根据名称来判定当前要访问哪一张表。 * mather.addURI("com.sky.db.BANKK", "teacher", 2); mather.addURI("com.sky.db.BANK", "student", 3); mather.addURI("com.sky.db.BANK", "people", 4);*/ }
在CRUD里面判断来访的URI是否正确
@Override public int delete(Uri uri, String selection, String[] selectionArgs) { // 假设匹配返回的code 是1 , if (mather.match(uri) == 1) { Log.d(TAG, "delete---"); //操作数据库... 假设这个应用的数据库里面有10张表。 student , teacher ,people ,data ,address DbHelper helper = new DbHelper(getContext()); SQLiteDatabase db = helper.getWritableDatabase(); //执行删除的方法,注意:这里的参数多半都是由外部程序传递进来的,我们一般不自己定义。 db.delete("account", selection, selectionArgs); } else { throw new IllegalArgumentException("uri错误,请检查。。。"); } // int result = mather.match(uri); return 0; }
在其他应用程序通过内容解析者操作内容提供者
public void insert(View v){ //其他应用程序使用contentprovider 暴露API接口,供其他人访问。 // 如果想操作contentprovider,就要通过一个contentresolver , 内容解析者 //1. 得到内容解析者 ContentResolver resolver = getContentResolver(); //2. 定义uri, 访问的口令 ,访问的路径 这里实际上给的是早前注册的口令,不过,口令前面必须加上content:// Uri url = Uri.parse("content://com.sky.db.BANK/bank"); //定义插入的数据 ContentValues values = new ContentValues(); values.put("name", "zhangsan"); values.put("money", 500); //3. 操作内容提供者中的增加方法 resolver.insert(url, values); }
四、内容观察者
1.观察者的概念
内容提供者在操作数据成功后,对外发出一个通知,关心这个通知的观察者就能收到通知。
getContext().getContentResolver().notifyChange(arg0, null);
其中两个参数的意义如下:
1. 属于什么样的uri对应的数据已经发生改变了
2. 内容观察者
* 如果内容观察者给null, 代表的时候数据发生改变,我就发出来一个通知,关心这个通知的人,就会收到改变的通知。
* 如果直接指定了一个对象,达标数据一旦改变,那么这个内容观察者就能收到通知
2.内容观察者使用步骤
注册一个内容观察者,观察指定的uri数据。
Uri uri = Uri.parse("content://com.sky.db.BANK/account");
//注册一个内容观察者
/**
* 让它观察指定的uri路径,如果通过了这个uri去改变了数据库的数据,俺么后面的内容观察者将会得到通知。
* 中间这个参数的意思是:true;只要匹配对了前半段的Uri,那么也能收到通知。false,代表全部uri,一个字母不漏,都要完全匹配,才能收到通知
*/
getContentResolver().registerContentObserver(uri, true, new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
System.out.println("来人啊,银行行长又来偷钱了..");
}
});