概述:
ContentProvider可以理解为一个Android应用对外开放的接口,只要是符合它所定义的Uri格式的请求,均可以正常访问执行操作。其他的Android应用可以使用ContentResolver对象通过与ContentProvider同名的方法请求执行,被执行的就是ContentProvider中的同名方法。所以ContentProvider很多对外可以访问的方法,在ContentResolver中均有同名的方法,是一一对应的。
原理图
Uri:
在Android中,Uri是一种比较常见的资源访问方式。而对于ContentProvider而言,Uri也是有固定格式的:
<srandard_prefix>://<authority>/<data_path>/<id>
<srandard_prefix>:ContentProvider的srandard_prefix始终是content://。
<authority>:ContentProvider的名称。
<data_path>:请求的数据类型。
<id>:指定请求的特定数据。
ContentProvider
ContentProvider也是Android应用的四大组件之一,所以也需要在AndroidManifest.xml文件中进行配置。而且某个应用程序通过ContentProvider暴露了自己的数据操作接口,那么不管该应用程序是否启动,其他应用程序都可以通过这个接口来操作它的内部数据。
Android附带了许多有用的ContentProvider,但是本篇博客不会涉及到这些内容的,以后有时间会再讲解。Android附带的ContentProvider包括:
- Browser:存储如浏览器的信息。
- CallLog:存储通话记录等信息。
- Contacts:存储联系人等信息。
- MediaStore:存储媒体文件的信息。
- Settings:存储设备的设置和首选项信息。
在Android中,如果要创建自己的内容提供者的时候,需要扩展抽象类ContentProvider,并重写其中定义的各种方法。然后在AndroidManifest.xml文件中注册该ContentProvider即可。
ContentProvider是内容提供者,实现Android应用之间的数据交互,对于数据操作,无非也就是CRUD而已。下面是ContentProvider必须要实现的几个方法:
- onCreate():初始化提供者。
- query(Uri, String[], String, String[], String):查询数据,返回一个数据Cursor对象。
- insert(Uri, ContentValues):插入一条数据。
- update(Uri, ContentValues, String, String[]):根据条件更新数据。
- delete(Uri, String, String[]):根据条件删除数据。
- getType(Uri) 返回MIME类型对应内容的URI。
除了onCreate()和getType()方法外,其他的均为CRUD操作,这些方法中,Uri参数为与ContentProvider匹配的请求Uri。
Tips:还有两个非常有意思的方法,必须要提一下,call()和bulkInsert()方法,使用call,理论上可以在ContentResolver中执行ContentProvider暴露出来的任何方法,而bulkInsert()方法用于插入多条数据。
在ContentProvider的CRUD操作,均会传递一个Uri对象,通过这个对象来匹配对应的请求。那么如何确定一个Uri执行哪项操作呢?需要用到一个UriMatcher对象,这个对象用来帮助内容提供者匹配Uri。它所提供的方法非常简单,仅有两个:
- void addURI(String authority,String path,int code):添加一个Uri匹配项,authority为AndroidManifest.xml中注册的ContentProvider中的authority属性;path为一个路径,可以设置通配符,#表示任意数字,*表示任意字符;code为自定义的一个Uri代码。
- int match(Uri uri):匹配传递的Uri,返回addURI()传递的code参数。
在创建好一个ContentProvider之后,还需要在AndroidManifest.xml文件中对ContentProvider进行配置,使用一个<provider.../>节点,一般只需要设置两个属性即可访问,一些额外的属性就是为了设置访问权限而存在的
- android:name:provider的响应类。
- android:authorities:Provider的唯一标识,用于Uri匹配,一般为ContentProvider类的全名。
ContentResolver
ContentResolver,内容访问者。可以通过ContentResolver来操作ContentProvider所暴露处理的接口。一般使用Content.getContentResolver()方法获取ContentResolver对象。上面已经提到ContentResolver的很多方法与ContentProvider一一对应,所以它也存在insert、query、update、delete等方法。
自定义ContentProvider
一、什么是自定义内容提供者
谈到内容提供者,大家就应该想到提供方和索要方,现在,我们想要做提供方,别人来访问我们的数据库,那我们就需要自定义内容提供者了。
二.思路:
1.提供方:ContentProvider
(1)创建数据库,自定义类继承SQLiteOpenHelper
(2)自定义内容提供者类,继承ContentProvider,重写insert/delete/update/query方法,向外界提供方法
(3)清单文件中注册内容提供者
2.索要方:ContentResolver
(1)通过Context的getContentResolver方法获得ContentResolver对象
(2)确定uri
(3)调用insert/delete/update/query方法访问数据库
自定义类继承SQLiteOpenHelper
public class MySqlHelper extends SQLiteOpenHelper {
public MySqlHelper(Context context) {
super(context, "user.db",null,1);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("create table student (_id integer primary key autoincrement ,name varchar(20),age integer)");
for (int i = 0; i < 5; i++) {
sqLiteDatabase.execSQL("insert into student values(null,?,?)",new String[]{"弟弟"+i,i+""});
}
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
自定义内容提供者类,继承ContentProvider
重新其他的方法
public class MyContentProvider extends ContentProvider {
private MySqlHelper mySqlHelper;
private SQLiteDatabase db;
@Override
public boolean onCreate() {
mySqlHelper = new MySqlHelper(getContext());
db = mySqlHelper.getReadableDatabase();
if (db != null){
return true;
}
return false;
}
@Override
public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
Cursor cursor = db.query("student", strings, s, strings1, null, null, s1);
return cursor;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues contentValues) {
return null;
}
@Override
public int delete(Uri uri, String s, String[] strings) {
return 0;
}
@Override
public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
return 0;
}
}
清单文件中注册内容提供者
内容索要方
(1)获取ContentResolver直接获取
进程间数据共享
进程间ContentProvider增删改查
自定义权限
1.使用场景
定义权限一般用于暴露出去的组件,提高安全性。Android允许一个应用(客户端)调用另一个应用(服务端)的组件。那么作为服务端的应用就得暴露相应的组件,客户端应用才能访问。当然,在暴露的时候,权限是非必须的,如果暴露的组件没有权限的话,那么任何的其他应用都可以来调用该组件;如果该组件申请了权限,那么只有拥有该权限的应用才能调用该组件。
网友评论