Content Provider

本文深入探讨了Android应用中使用内容提供者(ContentProvider)进行数据存储与检索的方法,包括创建自定义提供者、操作URI、查询与修改数据的流程,以及如何在不同场景下高效利用ContentResolver进行数据交互。

Content providers存储和检索数据并使其可以让所有apps访问,公开自己数据的两种方法:创建自己的provider或者把数据加到现有的provider里面。

基础

所有的content provider都现一个为provider查询和返回结果的公共接口,这是一个客户端直接使用的接口,通常都是通过contentresolver对象访问。

ContentResolver cr = getContentResolver();

URIs

   每个provider都会暴露一个公共的URI用来唯一定位它的数据集,提供多个数据集的content provider会为每个数据集提供一个URI,所有URI都是由“content://”开头。最好为URI提供一个constant(android.provider.Contacts.Phones.CONTENT_URI ),这会简化客户端的代码,而且让将来升级更干净。

查询ContentProvider

    You need three pieces of information to querya content provider:

  • The URI that identifies the provider
  • The names of the data fields you want to receive
  • The data types for those fields

如何查询

使用ContentResolver.query()or Activity.managedQuery()方法,后者可以让系统帮你管理cursor的状态。系统还提供了更好用的方法以便查询URI的某条记录,它们是ContentUris.withAppendedId() orUri.withAppendedPath()。

// Use the ContentUris method to produce the base URI forthe contact with _ID == 23.
Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);

// Alternatively, use the Urimethod to produce the base URI.
// It takes a string ratherthan an integer.
Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");

// Then query for thisspecific record:
Cursor cur = managedQuery(myPerson, null, null, null, null);


如果查询返回的是二进制数据,例如:图像或声音,数据会直接写进表里;通常,小量的数据(20k-50k)会直接写进表里,可以通过Cursor.getBlob()来访问,它将会返回一个二进制数组。

假如表的入口是content:URI,你必须调用ContentResolver.openInputStream()返回的inputStream对象来读取数据。

修改数据

    修改方式:增加新纪录、在现有纪录里增加值、批量更新现有纪录、删除纪录,所有的数据修改都是通过ContentResolver的方法实现的,调用其方法的前提是你必须有操作的权限。

    增加新纪录

ContentValues values = new ContentValues();

// Add Abraham Lincoln to contacts and make him a favorite.
values.put(People.NAME, "Abraham Lincoln");
// 1 = the new contact is added to favorites
// 0 = the new contact is not added to favorites
values.put(People.STARRED, 1);

Uri uri = getContentResolver().insert(People.CONTENT_URI, values);


增加新值

Uri phoneUri = null;
Uri emailUri = null;

// Add a phone number forAbraham Lincoln.  Begin with the URI for
// the new record justreturned by insert(); it ends with the _ID
// of the new record, so wedon't have to add the ID ourselves.
// Then append thedesignation for the phone table to this URI,
// and use the resulting URIto insert the phone number.
phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);

values.clear();
values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);
values.put(People.Phones.NUMBER, "1233214567");
getContentResolver().insert(phoneUri, values);

// Now add an email addressin the same way.
emailUri = Uri.withAppendedPath(uri, People.ContactMethods.CONTENT_DIRECTORY);

values.clear();
// ContactMethods.KIND isused to distinguish different kinds of
// contact methods, such asemail, IM, etc. 
values.put(People.ContactMethods.KIND, Contacts.KIND_EMAIL);
values.put(People.ContactMethods.DATA, "test@example.com");
values.put(People.ContactMethods.TYPE, People.ContactMethods.TYPE_HOME);
getContentResolver().insert(emailUri, values);  


像小型的icon图片或者音频短片可以直接put到values里面,但如果是照片或者是一首完整的歌,则必须把文件的content:URI放到表里并用文件的URI调用ContentResolver.openOutputStream()方法。为此,系统专门提供了MediaStore provider以处理这类数据。如下:

// Save the name and description of an image in aContentValues map.  
ContentValues values = new ContentValues(3);
values.put(Media.DISPLAY_NAME, "road_trip_1");
values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles");
values.put(Media.MIME_TYPE, "image/jpeg");

// Add a new record withoutthe bitmap, but with the values just set.
// insert() returns the URIof the new record.
Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);

// Now get a handle to thefile for that record, and save the data into it.
// Here, sourceBitmap is aBitmap object representing the file to save to the database.
try {
    OutputStream outStream = getContentResolver().openOutputStream(uri);
   sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
    outStream.close();
} catch (Exception e) {
    Log.e(TAG, "exception while writing image", e);
}


批量更新纪录

    参见ContentResolver.update()方法。

删除纪录

   参见ContentResolver.delete()方法

创建一个Content Provider

    创建必须要做的事:

²  建立一个存储数据的系统

²  继承ContentProvider类来提供数据的访问

²  在app的manifest里面声明它

继承ContentResolver类

1.  实现主要抽象方法:

query() 
insert() 
update() 
delete() 
getType() 
onCreate()

2.  定义一个public static finalUri CONTENT_URI,唯一标识

public static final Uri CONTENT_URI =
               Uri.parse("content://com.example.codelab.transportationprovider");

如果有子表,则要保证它们有相同的授权,而且要为每个子表定义一个唯一的URI,如:

content://com.example.codelab.transportationprovider/train 
content://com.example.codelab.transportationprovider/air/domestic 

3.  定义返回给客户端的列名,public static类型的,而且要保证有个自增的ID。

4.  仔细文档化每列的数据类型

5.  如果要存储大文件,暴露给客户端的字段需要包含conent:URI,以便存储和访问文件

6.  声明它

<provider android:name="com.example.autos.AutoInfoProvider"
          android:authorities="com.example.autos.autoinfoprovider" 
          . . . />
</provider>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值