1.什么是ContentProvider
内容提供程序管理对结构化数据集的访问。它们封装数据,并提供用于定义数据安全性的机制。 内容提供程序是连接一个进程中的数据与另一个进程中运行的代码的标准界面。
如果想要访问内容提供程序中的数据,可以将应用的 Context 中的 ContentResolver 对象用作其他应用来与ContentProvider 通信。 ContentResolver 对象会与内容提供者对象(即实现 ContentProvider 的类实例)通信。 内容提供者对象从其他应用接收数据请求,执行请求的操作并返回结果。
contentprovider以类似关系型数据库中表格的形式向其他应用提供数据。Contentprovider与应用中的数据存储层协调已达到提供数据给各个接口或者Android中的组件 :
- 使你的应用实现与其他应用共享数据;
- 给小部件发送数据;
- 通过searchrecentsuggestionsprovider搜索框架返回应用程序的自定义搜索建议;
- 通过abstractthreadedsyncadapter实现本地应用于服务器端数据的同步
- 使用CursorLoader加载数据到UI;
当客户端要访问contentprovider中的数据的时候,使用应用中Context中的ContentResolver对象。Contentprovider接收到客户端的请求,做出响应,然后返回结果。
ContentResolver提供例如 对数据的增删改查。
以下是一般的访问数据的流程:
Activity或者Fragment通过调用CursorLoader来获取数据,CursorLoader通过ContentResolver获取ContentProvider中的数据
注意:为了访问ContentProvider你的应用需要在Androidmanifest文件中申请权限。
以下 <uses-permission> 元素会请求对用户字典提供程序的读取访问权限:
<uses-permission android:name="android.permission.READ_USER_DICTIONARY">
2.创建自定义ContentProvider
a).设计原始数据存储。ContentProvider一两种方式提供数据:
i.文件数据
通常存储在文件中的数据,如照片、音频或视频。 将文件存储在您的应用的私有空间内。 您的提供程序可以应其他应用发出的文件请求提供文件句柄。
“ii.结构化”数据
通常存储在数据库、数组或类似结构中的数据。 以兼容行列表的形式存储数据。行表示实体,如人员或库存项目。 列表示实体的某项数据,如人员的姓名或商品的价格。 此类数据通常存储在 SQLite 数据库中,但您可以使用任何类型的持久存储。
b).设计ContentURI
i.设计授权:
提供程序通常具有单一授权,该授权充当其 Android 内部名称。为避免与其他提供程序发生冲突,您应该使用互联网网域所有权(反向)作为提供程序授权的基础。 由于此建议也适用于 Android 软件包名称,因此您可以将提供程序授权定义为包含该提供程序的软件包名称的扩展名。 例如,如果您的 Android 软件包名称为 com.example.,则应为提供程序提供 com.example..provider 授权
ii.设计路径结构
开发者通常通过追加指向单个表的路径来根据权限创建内容 URI。 例如,如果您有两个表:table1 和 table2,则可以通过合并上一示例中的权限来生成 内容 URI com.example..provider/table1 和 com.example..provider/table2。路径并不限定于单个段,也无需为每一级路径都创建一个表。
iii.处理内容 URI ID
按照惯例,ContentProvider通过接受末尾具有行所对应 ID 值的内容 URI 来提供对表中单个行的访问。ContentProvider会将该 ID 值与表的 _ID 列进行匹配,并对匹配的行执行请求的访问。
content://media/internal/images 这个URI将返回设备上存储的所有图片
content://contacts/people/ 这个URI将返回设备上的所有联系人信息
content://contacts/people/45 这个URI返回单个结果(联系人信息中ID为45的联系人记录)
c)实现 ContentProvider 的子类
抽象类 ContentProvider 定义了六个抽象方法,必须将这些方法作为自己具体子类的一部分加以实现。 所有这些方法(onCreate() 除外)都由一个尝试访问ContentProvider的应用调用:
- query()
从提供程序检索数据。使用参数选择要查询的表、要返回的行和列以及结果的排序顺序。 将数据作为 Cursor 对象返回。 - insert()
在提供程序中插入一个新行。使用参数选择目标表并获取要使用的列值。 返回新插入行的内容 URI。 - update()
更新提供程序中的现有行。使用参数选择要更新的表和行,并获取更新后的列值。 返回已更新的行数。 - delete()
从提供程序中删除行。使用参数选择要删除的表和行。 返回已删除的行数。 - getType()
返回内容 URI 对应的 MIME 类型。实现内容提供程序 MIME 类型部分对此方法做了更详尽的描述。 - onCreate()
初始化提供程序。Android 系统会在创建提供程序后立即调用此方法。 请注意,ContentResolver 对象尝试访问提供程序时,系统才会创建它。
请注意,这些方法的签名与同名的 ContentResolver 方法相同。
在实现这些方法时应考虑以下事项:
- 所有这些方法(onCreate() 除外)都可由多个线程同时调用,因此它们必须是线程安全方法。
- 避免在 onCreate() 中执行长时间操作。将初始化任务推迟到实际需要时进行。
- 尽管必须实现这些方法,但代码只需返回要求的数据类型,无需执行任何其他操作。 例如,你可能想防止其他应用向某些表插入数据。 要实现此目的,您可以忽略 insert() 调用并返回 0。
3.使用ContentProvider
前面已经说过ContentProvider和ContentResolver有着一样(函数名、返回类型、参数)六个的方法:
当其他应用想要获取ContentProvider中的数据的时候只要在代码中获得ContentResolver对象,然后调用这几个方法就可以。
下面以通过ContentProvider获取系统联系人为例:
步骤大致如下:
i.获取ContentResolver对象;
ii.调用query方法;
我们通过Android获得系统联系人ContentProvider的URi,然后当做参数传递给query()函数就行了。
下面是Mainactivity中的代码:
package com.example.geekp.mcontentprovider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.v4.content.ContentResolverCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ContentResolver resolver = getContentResolver();
//获取联系人的Uri
Uri uri = ContactsContract.Contacts.CONTENT_URI;
Cursor cursor = resolver.query(uri, new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME}, null, null, null);
if (null != cursor) {
while (cursor.moveToNext()) {
System.out.println("用户ID:" + cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID)));
System.out.println("姓名:" + cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
}
}
cursor.close();
}
}
看看还要在Androidmanifest配置文件中申请读取系统权限:
<!--所需权限-->
<uses-permission android:name="android.permission.READ_CONTACTS" />
效果图:
使用ContentProvider就是这么简单了!