版权声明:本章节为安卓巴士博主原创文章,未经授权不得以任意形式转载发布/发表,违者将依法追究责任
7.1 内容提供者简介
内容提供者,也即ContentProvider,是Android中的四大组件之一。从这里也能知道它在Android开发中的的重要性,所以是必须要掌握的了。同时它也是四大组件里面最简单最容易入手的一个。ContentProvider是以类似数据库中表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”。有点像调用web接口一样,我们在的开发的时候看不到存在数据库里面的数据,但是我们只要知道了接口地址后,按照对应的规则进行调用,就可以获取到数据。差不多是一样的用法。
7.2 内容提供者机制简单讲解
调用过程
在创建ContentProvider前,首先要实现底层的数据源,数据源包括数据库、文件系统或网络等,然后继承ContentProvider类中实现基本数据操作的接口函数。调用者不能直接调用ContentProvider的接口函数,需要通过ContentResolver对象,通过URI间接调用ContentProvider。
交互关系
在ContentResolver对象与ContentProvider进行交互时,通过URI确定要访问的ContentProvider数据集。在发起的一个请求的过程中,Android系统根据URI确定处理这个查询的ContentProvider,然后初始化ContentProvider所有需要的资源,这个初始化的工作是Android系统完成的,无需开发人员关心。一般情况下只有一个ContentProvider对象,但却可以同时与多个ContentResolver进行交互。
所需权限
根据功能需要自己进行添加 例如在开发读取通讯录功能的时候,所需的权限是下面:
<uses-permission android:name='android.permission.READ_CONTACTS'/><uses-permission android:name='android.permission.WRITE_CONTACTS'/>
在开发读取短信功能的时候,所需的权限是下面:
<uses-permission android:name='android.permission.READ_SMS' />
根据自己开发的项目灵活进行配置
数据来源
在Android系统中,ContentProvider共享的数据多来自系统自带应用,比如联系人信息,图片库,音频库等应用,或者是共享自己或者其他开发者开发的应用里面的文件、数据库内存储的数据。
ContentResolver
ContentResolver:内容解析器,是为了方便在应用之间交换数据。
当一个应用程序需要把自己的数据暴露给其他应用程序使用时,该应用程序可以通过提供ContentProvider来实现; 而其他应用程序需要使用这些数据时,不管提供数据的应用程序是否启动,可以通过ContentResolver来操作ContentProvider暴露的数据。包括增加数据insert()、删除数据delete()、修改数据update()、查询数据query()等。 虽然大部分使用ContentProvider操作的数据都来自于数据库,但是也可以来自于文件、SharedPreferences、XML或网络等其他存储方式。
URI
Uri统一资源标识符:Uri是ContentResolver和ContentProvider进行数据交换的标识。 形如:content://com.qq.contacts/user/1
其中标准前缀协议部分:以“content://”开头,表明是以ContentProvider的方式进行数据交换。
Uri的authority部分:'com.qq.contacts'该部分是暴露数据的app数据的包名。 Uri的path部分,user,表明判断请求的路径
Uri的id部分,表明请求要操作的id值;如果不是操作具体某一id的数据,此部分可以去除。
7.3 访问其他应用中的数据
这一部分开始到代码实战部分了,先前讲到ContentProvider可以读取其他应用的联系人、短信、通话记录、音频文件数据等等。这一部分以具体的例子来实际熟悉下用法。最常见的就是读取手机联系人了。
ContentResolver的基本用法
ContentResolver是通过URI来查询ContentProvider中提供的数据。除了URI以外,还必须知道需要获取的数据段的名称,以及此数据段的数据类型。如果你需要获取一个特定的记录,你就必须知道当前记录的ID,也就是URI中D部分。
前面也提到了ContentProvider是以类似接口的方式将数据暴露出去,那么ContentResolver也将采用类似数据库的操作来从ContentProvider中获取数据。下面是ContentResolver的主要方法:
query(Uri, String[], String, String[], String)返回final Cursor
query方法的参数依次为:请求的Uri,列名数组,查询条件,selectionArgs替换占位符的数组,排序sortOrder语句insert(Uri, ContentValues)返回final Uri
insert方法的参数依次为:请求的Uri,传递的参数ContentValuesupdate(Uri, ContentValues, String, String[])返回final int
update方法的参数依次为:请求的Uri,传递的参数ContentValues,String实例对象,String引用对象数组delete(Uri, String, String[])返回final int
delete方法的参数依次为:请求的Uri,String实例对象,String数组
读取系统联系人
// 读取系统联系人示例// 在AndroidManifest.xml中添加访问联系人数据的权限
private void readContacts() {
Cursor cursor = null;
try {
//查询联系人数据
//ContactsContract.CommonDataKinds.Phone类已经封装好了URI,NAME,NUMBER等信息
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null, null);
while (cursor.moveToNext()) {
//获取联系人姓名
String displayName = cursor.getString(cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
//获取联系人手机号
String number = cursor.getString(cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactsList.add(displayName + '\n' + number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
}注意:清单文件里面添加权限声明:
<uses-permission android:name='android.permission.READ_CONTACTS'/><uses-permission android:name='android.permission.WRITE_CONTACTS'/>
7.4 创建自己的内容提供者
前面说到我们开发的应用去读取系统应用的数据(例如:通讯录、短信、音频数据等),那么我们是否可以自己在开发应用的时候,将本应用的数据以内容提供者的方式提供给别的应用来操作呢?当然也是可以的。
我们所要做的就是继承ContentProvider这个抽象类,然后重写它里面的各种方法。
外部开发者可以通过我们定义的Uri及传值规则来操作数据的增删改查。
示例代码
public class MyContentProvider extends ContentProvider { private final static int CONTACT = 1; private static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static {
uriMatcher.addURI('com.abc.mycontentprovider','contact',CONTACT);
} private MyDBHelp dbHelp; @Override
public int delete(Uri uri, String selection, String[] selectionArgs) { int id =0; if(uriMatcher.match(uri) == CONTACT){
SQLiteDatabase database = dbHelp.getWritableDatabase();
id= database.delete('contact', selection, selectionArgs);
contentResolver.notifyChange(uri,null);
} return id;
} @Override
public String getType(Uri uri) { // TODO: Implement this to handle requests for the MIME type of the data
// at the given URI.
throw new UnsupportedOperationException('Not yet implemented');
} @Override
public Uri insert(Uri uri, ContentValues values) {
Uri u = null; if(uriMatcher.match(uri) == CONTACT){
SQLiteDatabase database = dbHelp.getWritableDatabase(); long d = database.insert('contact', '_id', values);
u = ContentUris.withAppendedId(uri,d);
contentResolver.notifyChange(u,null);
} return u;
} private ContentResolver contentResolver; @Override
public boolean onCreate() {
Context context = getContext();
contentResolver = context.getContentResolver();
dbHelp = new MyDBHelp(context,'contact.db',null,1); return true;
} @Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
Cursor cursor = null; if(uriMatcher.match(uri) == CONTACT){
SQLiteDatabase database = dbHelp.getReadableDatabase();
cursor = database.query('contact', projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(contentResolver,uri);
} return cursor;
} @Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) { // TODO: Implement this to handle requests to update one or more rows.
throw new UnsupportedOperationException('Not yet implemented');
} private static class MyDBHelp extends SQLiteOpenHelper{ public MyDBHelp(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version);
} @Override
public void onCreate(SQLiteDatabase db) {
String sql = 'create table contact(_id integer primary key autoincrement,' + 'name text not null,number text not null);';
db.execSQL(sql);
} @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onCreate(db);
}
}
}在清单文件里面对新增的自定义ContentProvider加以声明。例如:
<provider android:name='.MyContentProvider' android:authorities='com.abc.MyContentProvider' android:exported='true' />
authorities 指明内容提供者的唯一标识,外部其他的应用来调用的时候通过此标识来找到exported true意为允许外部的其他应用访问
接下来写另一个应用程序,作为调用的一方通过ContentProvider去读取上一个应用程序里面暴露的方法,进而获取或者操作所需的数据。 在另一个应用里面,那么它要访问的Uri就为
Uri uri = Uri.parse('content://com.abc.mycontentprovider/contact')其访问数据及增删改的操作类比《7.3访问其他应用数据》中的示例。
7.5 小结与点评
欢迎大家提出完善意见以补充。





































苏公安网备 32011402010933号