Android系列之Content Provider

  有时候,我们自己的应用程序想要使用的数据可能是存储于其他应用程序之中。那么,就涉及到了数据在不同应用之间共享的问题。为了使得数据可以在程序之间共享,并且保证数据的安全性,Android提供了Content Provider机制。
  对于想使用其他应用程序的数据来说,就需要了解如何调用其他APP的CP(Content Provider)。通常来说,我们通过调用ContentResolver接口来使得用户间接调用其他应用程序的CP中的数据。该接口可通过getContentResolver()方法来得到一个实例对象。如:

ContentResolver cr = getContentResolver();

之后通过ContentResolver的方法来对数据进行CRUD操作。这个过程我们完全不需要与CP进行交互操作。事实上,每一种CP只会产生一个实例,然后与多个不同APP或者进程的ContentResolver进行交互。
  对于CP的CRUD操作,有区别于SQLite的操作。在CP中,所有的操作都依赖于URI。
  URI:统一资源定位。其中统一的开头均为:“content://”这就类似于一种协议如”http://”。代表了,这部分数据由CP控制。
如果我们自己要定义URI,定义一个参数来代表URI是一个不错的选择。Android建议使用CONTENT_URI来代表平台上的所有URI,如代表电话号码或照片的URI为:

android.provider.Contacts.Phones.CONTENT_URI 
android.provider.Contacts.Photos.CONTENT_URI 

  定位到了数据,那么就要了解数据到底是怎么存储的。
  CP希望数据的存储能够尽量的简单化,每一行代表一份记录,每一列代表数据的类型或者其意义。每一条记录都带有一个数值型的ID为“_ID”。每一个ID代表了表中数据的唯一记录标识。通过该ID我们可以查到我们想要的数据。如:

//如:希望查询ID为45的数据
Uri person = ContentUris.withAppendedId(People.CONTENT_URI,  45);
//然后就可以进行数据查询
Cursor cur = managedQuery(person, null, null, null);

CRUD都类似于此操作。关键是要获取正确的URI信息。
  那么,了解了如何调用其他APP的CP后,我们要是希望给自己的APP添加CP功能,该如何操作呢?这里的操作稍微繁琐点,但总结下来也就几步:
  ①、我们需要建立一个数据库来存储我们的数据,通常使用SQLiteDatabase。
  ②、创建一个子类,继承自CP,并实现其中的CRUD方法。
  ③、在AndroidManifest文件中对我们自定义的CP进行注册。
 ① SQLIte的创建等操作就不细说了。首先从继承自CP的子类来了解。
 ② 当我们自定义的类继承了CP之后我们需要实现其中的CRUD方法,同时,我们还需要重写其中的onCreate()和getType()方法。
  对于查询操作,我们要返回一个cursor游标,由于CP会在不同的线程或进程中调用,所以我们希望它是线程安全的,所以通常使用SQLiteDatabase的query()方法。
  在重写这些方法之外,还需要几步来使得我们的操作更加简单化。
- 定义一个静态的常量,来代表content。通常我们使用路径名代表URI的权限即:content://路径名。如果CP还有子表,那么可以在权限之后加上相应的表名,作为URI的标识:content://路径名/表名。
- 定义一些CP返回给用户的列名,若没有定义的话,则会使用基本数据库中的列名。
-如果,我们需要处理的数据类型是一些较新的数据类型,我们还需要定义一些MIME的数据类型,以便CP的getType()方法可以返回。MIME有两种类型,一种是单一记录如:
vnd.android.cursor.item/vnd.yourcompanyname.contenttype
举例来说:

//For example, a request for train record 122, like this URI,
content://com.example.transportationprovider/trains/122
//might return this MIME type:
vnd.android.cursor.item/vnd.example.rail

另一种是多条记录如:vnd.android.cursor.dir/vnd.yourcompanyname.contenttype
举例来说:

//For example, a request for all train records, like the following URI,
content://com.example.transportationprovider/trains
//might return this MIME type:
vnd.android.cursor.dir/vnd.example.rail
  • 如果存储的数据较大,如bitmap位图。那么暴露给用户的数据事实上是一个包含了“content://URI”的字符串。这部分可以使用户获得数据文件。这条记录应该包含了另一个域“_data”这部分包含了文件在设备上的确切路径。这部分不是给用户的,而是给ContentResolver的。用户通过ContentResolver.getInputStream()方法来调用。ContentResolver就会去访问“_data”域因为它有着比用户更高的权限。
      ③  最后便是在AndroidManifest文件中注册了。
<provider name="com.example.autos.AutoInfoProvider"                         authorities="com.example.autos.autoinfoprovider"           . . . />provider>

name代表了CP的子类,authorities就代表了CONTENT_URI部分。值得注意的是,这个authorities权限是代表的该APP的CP而不是CP中的各个表。
  至此,完成了CP的自定义。关键部分任然是URI。以及CRUD操作的重写。

你可能感兴趣的:(Android,android)