Android四大组件-ContentProvider

最后更新于:2022-04-01 11:18:16

## 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的使用。 首先来了解一下通话记录和联系人的表结构。 这是手机中部分表: ![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-20_5717152a3315c.jpg "") 通话记录在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 ![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-20_5717152a4263d.jpg "") 数据类型表中需要注意的是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(); } ~~~ **简单使用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" }; ~~~ **—>增删该查操作都是第一步得到ContentResolver操作对象,第二步执行已经定义好的方法。** ~~~ <!-- 访问联系人的ContentProvider组件的权限 --> <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.WRITE_CONTACTS"/> ~~~ **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); ~~~ **这个方法值得注意的是返回的是一个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); ~~~ **2.4查询所有联系人** ~~~ ContentResolver resolver = getContentResolver(); // 先从联系人表中查询所有人的信息 Cursor cursor = resolver.query(contactUri, conColumn, null, null, null); ~~~ ##二、自定义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); } } } ~~~ **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; } } ~~~ **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" /> ~~~ **注意:还需要添加访问该provider的权限和修改的操作权限,否则其他程序不能访问或操作** ~~~ <!-- 声明访问该组件的权限 --> <permission android:name="com.beiing.contentprovider_selfdefine.READ_WRITE"/> ~~~ **4)在其他程序中使用** 和上面使用类似,不赘述了。 [源码](http://download.csdn.net/detail/u011102153/9099743)
';