文档开发者中心
我的

第7章 ContentProvider组件从入门到熟悉(转载)

版权声明:本章节为安卓巴士博主原创文章,未经授权不得以任意形式转载发布/发表,违者将依法追究责任


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,传递的参数ContentValues

  • update(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 小结与点评

欢迎大家提出完善意见以补充。


点赞
收藏
回复
分享
举报
浏览1899 编辑于2019-12-03 10:35未知归属地
全部评论
最多点赞
最新发布
最早发布
暂无评论
暂无评论
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

目录 收起
7.1 内容提供者简介
7.2 内容提供者机制简单讲解
调用过程
交互关系
所需权限
数据来源
ContentResolver
URI
7.3 访问其他应用中的数据
ContentResolver的基本用法
读取系统联系人
7.4 创建自己的内容提供者
7.5 小结与点评
了解社区公约,与您携手共创和谐专业的开发者社区。