ContentProvider:内容提供者

来源:互联网 发布:高效文件复制软件 编辑:程序博客网 时间:2024/05/04 11:50

ContentProvider:内容提供者

ContentProvider简介: 
当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。 
Uri类简介 
Uri代表了要操作的数据,Uri主要包含了两部分信息:1.需要操作的ContentProvider ,2.对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成: 
1.scheme:ContentProvider(内容提供者)的scheme已经由Android所规定为:content://。 
2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。 
3.路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下: 
• 要操作contact表中id为10的记录,可以构建这样的路径:/contact/10 
• 要操作contact表中id为10的记录的name字段, contact/10/name 
• 要操作contact表中的所有记录,可以构建这样的路径:/contact

本篇主要围绕通话记录和联系人讲解ContentProvider的使用。

首先来了解一下通话记录和联系人的表结构。 
这是手机中部分表: 
这里写图片描述 
通话记录在calls表中,联系人表主要有三个:raw_contacts、data、mimetype表。 
–联系人记录 
–存放联系人信息的表(注意表结构): 
联系人信息表:raw_contacts 
–_id 
–display_name联系人名称

联系人数据表:data 
–_id 
–raw_contact_id(外键,raw_contacts表的_id) 
–data1 
–data2 
–mimetype_id(数据类型,如电话,邮箱,地址 外键(mimeypes))

数据类型表:mimeypes 
–_id 
–mimetype 
这里写图片描述 
数据类型表中需要注意的是name、phone_v2、email_v2字段,对应id是7、5、1;


一、ContentResolver的使用

1)定义ContentProvieder组件提供的内容的Uri接口 
2)定义被访问的表中的字段 
3)添加访问权限

简单使用1:查询最近联系人记录

// 访问拨号应用下的ContentProvieder组件提供的内容的Uri接口private Uri callUri = CallLog.Calls.CONTENT_URI;// 被访问的表中的字段private String[] columns = { CallLog.Calls._ID, CallLog.Calls.NUMBER,CallLog.Calls.DATE, CallLog.Calls.TYPE };private void loadData() {        // 使用ContentResolver访问拨号记录应用下的ContentProvider组件提供的数据库中表的数据        // 得到ContentResolver对象        ContentResolver resolver = getContentResolver();        // 查询uri代表的资源(从 Uri代表的表中进行查询)        Cursor cursor = resolver.query(callUri, columns, null, null, null);        while (cursor.moveToNext()) {            long id = cursor.getLong(0);            String number = cursor.getString(1);            long time = cursor.getLong(2);            int type = cursor.getInt(3);            String date = new SimpleDateFormat("yyyy-MM-dd E HH:mm:ss")                    .format(new Date(time));            String types = (type == 1 ? "拨入" : (type == 2 ? "拨出" : "未接"));            datas.add(new CallInfo(id, number, date, types));        }        adapter.notifyDataSetChanged();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

简单使用2:查询手机联系人,然后执行增删改操作 
需要了解联系人数据库中有哪些表及表的结构:通过adb shell可以查看。 
–联系人记录 
–存放联系人信息的表(注意表结构): 
联系人信息表:raw_contacts 
–_id 
–display_name联系人名称 
联系人数据表:data 
–_id 
–raw_contact_id(外键,raw_contacts表的_id) 
–data1:电话、邮箱、姓名等信息 
–data2 
–mimetype_id(数据类型,如电话,邮箱,地址 外键(mimeypes)) 
数据类型表:mimeypes 
–_id 
–mimetype 
– mimetype_id=1:邮箱 
– mimetype_id=5:电话 
– mimetype_id=7:姓名

// 访问raw_contacts这张表的Uri    private Uri contactUri = Uri            .parse("content://com.android.contacts/raw_contacts");    private String[] conColumn = { "_id", "display_name" };    // //访问data这张表的Uri    private Uri dataUri = Uri.parse("content://com.android.contacts/data");    private String[] dataColumn = { "data1" };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

—>增删该查操作都是第一步得到ContentResolver操作对象,第二步执行已经定义好的方法。

<!-- 访问联系人的ContentProvider组件的权限 -->    <uses-permission android:name="android.permission.READ_CONTACTS"/>    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
  • 1
  • 2
  • 3

2.1添加联系人: 
// 向联系人表raw_contacts中添加新的联系人信息

ContentValues value = new ContentValues();value.put("display_name", name);value.put("display_name_alt", name);// 返回新插入的记录Uri,Uri中包含了_id// content://com.android.contacts/raw_contacts/#8    Uri datasUri = getContentResolver().insert(contactUri,value);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这个方法值得注意的是返回的是一个uri,也就是新增的这条数据的uri,如果想得到该条记录的id可以调用这个方法: 
long _id = ContentUris.parseId(datasUri);

–姓名: 
value.put(“data1”, name); 
value.put(“mimetype”,”vnd.android.cursor.item/name”); 
–电话: 
value.put(“data1”, phone); 
value.put(“mimetype”,”vnd.android.cursor.item/phone_v2”); 
–邮件: 
value.put(“data1”, email); 
value.put(“mimetype”,”vnd.android.cursor.item/email_v2”);

2.2删除联系人:都是很简单的操作 
// 再从联系人表中删除信息 
getContentResolver().delete(contactUri, “_id=” + id,null);

2.3修改联系人:

value.put("display_name", name);value.put("display_name_alt", name);long id = Long.parseLong(String.valueOf(datas.get(curItemPosition).get("id")));// 更新联系人信息getContentResolver().update(contactUri, value,"_id=" + id, null);
  • 1
  • 2
  • 3
  • 4
  • 5

2.4查询所有联系人

ContentResolver resolver = getContentResolver();// 先从联系人表中查询所有人的信息Cursor cursor = resolver.query(contactUri, conColumn, null, null, null);
  • 1
  • 2
  • 3

二、自定义ContentProvider

1.步骤: 
1)声明该contentProvider的唯一标识,通常使用包名加数据库名,必须小写 
2)为该组件中可以被外界访问的数据库中的资源定义Code标识,不对外界开放的不用定义 
3)定义访问资源的Uri的匹配器对象–使用该类生成被访问的资源的Uri 
4)UriMatcher添加访问uri 
5)清单文件中注册组件 name authorities 
6)声明访问该组件的权限 
7)重写provider的增删改查方法

2.实现 
1)自定义数据库

public class DBHelper extends SQLiteOpenHelper {    public DBHelper(Context context) {        super(context, "users.db", null, 1);    }    @Override    public void onCreate(SQLiteDatabase db) {        // TODO 初始化数据库        db.execSQL("create table t_user(_id integer primary key,uname,upass,money)");        db.execSQL("create table t_order(_id integer primary key,user_id,price,productname)");        db.execSQL("insert into t_user(uname,upass,money) values('lisa','123',200)");        db.execSQL("insert into t_user(uname,upass,money) values('zhangsan','1234',2000)");    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        // TODO 数据库升级时执行该方法        if (newVersion > oldVersion) {            db.execSQL("drop table if exists t_user");            db.execSQL("drop table if exists t_order");            onCreate(db);        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

2)按上述步骤定义ContentProvider

public class UserContentProvider extends ContentProvider {    // 声明该ContentProvider的唯一标识--通常使用包名+数据库名--必须小写    public static final String AUTHORITY = "com.beiing.contentprovider_selfdefine.users";    // 为该组件中可以被外界访问的数据库中的资源定义Code标识    public static final int CODE_USER = 1;    public static final int CODE_ORDER = 2;    // 定义访问资源的Uri的匹配器对象--使用该类生成被访问的资源的Uri    private static UriMatcher uriMatcher;    static {        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);        // content://com.beiing.contentprovider_selfdefine.users/user        uriMatcher.addURI(AUTHORITY, "user", CODE_USER);        // content://com.beiing.contentprovider_selfdefine.users/order        uriMatcher.addURI(AUTHORITY, "order", CODE_ORDER);    }    private DBHelper dbHelper;    @Override    public boolean onCreate() {        // TODO 初始化 数据库操作的工具类        dbHelper = new DBHelper(getContext());        return false;    }    @Override    public Cursor query(Uri uri, String[] projection, String selection,            String[] selectionArgs, String sortOrder) {        SQLiteDatabase db = dbHelper.getReadableDatabase();        Cursor cursor = null;        int code = uriMatcher.match(uri);        switch (code) {        case CODE_USER:            cursor = db.query("t_user", projection, selection, selectionArgs,                    null, null, sortOrder);            break;        case CODE_ORDER:            break;        }        return cursor;    }    @Override    public Uri insert(Uri uri, ContentValues values) {        // TODO 向数据库中插入数据        SQLiteDatabase db = dbHelper.getWritableDatabase();        if (uriMatcher.match(uri) == CODE_USER) {            long id = db.insert("t_user", null, values);            // 返回新插入的记录的 Uri,回忆插入新数据时可以通过返回的uri得到id            // content://com.beiing.contentprovider_selfdefine.users/user/6            return ContentUris.withAppendedId(uri, id);        }        return null;    }    @Override    public int delete(Uri uri, String selection, String[] selectionArgs) {        // TODO 删除数据库中的数据        SQLiteDatabase db = dbHelper.getWritableDatabase();        int num = 0;        if (uriMatcher.match(uri) == CODE_USER) {            num = db.delete("t_user", selection, selectionArgs);        }        return num;    }    @Override    public int update(Uri uri, ContentValues values, String selection,            String[] selectionArgs) {        // TODO 修改数据库中的数据        SQLiteDatabase db = dbHelper.getWritableDatabase();        if (uriMatcher.match(uri) == CODE_USER) {            return db.update("t_user", values, selection, selectionArgs);        }        return 0;    }    @Override    public String getType(Uri uri) {        return null;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

3)清单文件中注册内容提供器

<!-- 注册 ContentProvider组件               android:authorities:声明该组件的唯一标识              android:permission:声明该组件的权限              android:exported="true":声明该组件可以被外界应用访问        --><provider       android:name="com.beiing.contentprovider_selfdefine.contentprovider.UserContentProvider"            android:authorities="com.beiing.contentprovider_selfdefine.users"            android:permission="com.beiing.contentprovider_selfdefine.READ_WRITE"android:exported="true"/>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意:还需要添加访问该provider的权限和修改的操作权限,否则其他程序不能访问或操作

<!-- 声明访问该组件的权限 -->    <permission android:name="com.beiing.contentprovider_selfdefine.READ_WRITE"/>
  • 1
  • 2

4)在其他程序中使用 
和上面使用类似,不赘述了。

源码

0 0