Content Provider 详解

几个概念:Cursor、 Content provider 、 Uri  、contentresolver

1、

Cursor : 个人理解为数据库中的一行数据,它是每行数据的集合。它是一个类。通过它的一系列方法,我们可以对数据库中的每行进行定位,我们还可以知道每一列的信息。比如:

cursor(游标).moveToFirst(),表示定位到第一行,然后我们通过其他方法可以知道每列的名称,每列的数据类型等。

2、

Content Provider :内容提供者,我们一个application中的其他类假如想操作数据库中的数据的话,就可以直接对此进行操作,而避免了对数据库进行直接操作,再说了,数据库这些个东西有权限要求的,我们不可能把数据库直接暴露出来,所以,通常采用这种形式。其实他就是一个提供数据访问的网站,我们要访问它的话,就得知道他的域名。 android:authorities   .   在minifest.xml中配置如下:(包含两个部分,name 与 anthorities)

<provider android:name=".PersonProvider" android:authorities=

"com.sharpandroid.providers.personprovider"/>

   当某个应用,可能是外部的,可以通过这两个属性来找到这个Content Provider了。  

   Content Provider 支持在多个应用中存储和读取数据。这也是跨应用共享数据的唯一方式。在android系统中,没有一个公共的内存区域,供多个应用共享存储数据。

3、

Uri: 这个东西就是  提供者提供数据的详细地址,到底是哪些数据,用此来对数据进行过滤操作。假如说,Content Provider是一个DNS,域名的话。那么Uri可以认为是IP地址,我们通过此IP地址找到我们所需要的数据。知道了它,就知道了数据在哪,然后通过调用某个方法,返回一个Cursor对象。数据包含在这个其中。

它有几个部分组成:  content://com.sharpandroid.provider.personprovider/person/2

其中,scheme:content 表示这个数据被一个content类型的数据(内容提供者)所控制。

      authrities:   com.sharpandroid.provider.personpervider表示权限部分,就是contentprovider的域名部分。。

             path:用来请求数据类型的路径。person/2  。请求的是person/2,还可以是school/student等。

                ID:被请求特定记录的ID。

还有一点需要注意,需要被数据不一定来自数据库,还可以来自其他地方,比如说XML,文本等。

Uri.parse()这个方法可以将字符串解析为Uri的形式。

  我们一般通过UriMather类用来对我们 我们传递过来的IP进行自动匹配。

private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);

private static final int PERSONS = 1;

private static final int PERSON = 2;

private DatabaseHelper databaseHelper

static{

matcher.addURI("com.sharpandroid.providers.personprovider",

"person", PERSONS);  //对特定的值进行匹配,成功返回1.

matcher.addURI("com.sharpandroid.providers.personprovider",

"person/#", PERSON);//#表示通配符,如果匹配成功,返回匹配码2.

}

4、

contentresovler:

那么我们该如何使用contentprovider呢?

我们一般通过contentresolver来对内容提供者提供的数据进行操作。

这个类提供了与Content Provider 相同的四个方法,增删改查方法。

如果需要查询contentprovider数据集的特定记录(行),还需要知道该记录的ID的值。

构建查询

查询就是输入URI等参数,其中URI是必须的,其他是可选的,如果系统能找到URI对应的contentprovider将返回一个Cursor对象。

可以通过ContentResolver.query()或者Activity.managedQuery()方法。两者的方法参数完全一样,查询过程和返回值也是相同的。

其他注意点:

query()方法,返回值是Cursor实例,用于迭代请求的数据。Cursor是一个接口。android为该接口提供了一些只读的(和 JDBC的ResultSet不一样,后者还提供可写入的可选特性)Cursor实现。比如SQLiteCursor,可迭代SQLite数据库中的数据。可以通过SQLiteDatabase类的query()方法获取到该Cursor实例。还有其他的Cursor实现,比如 MatrixCursor,用于数据不是存储在数据库的情况下。

因为Contentprovider可能被多个ContentResolver对象在不同的进程和线程中调用,因此实现Contentprovider必须考虑线程安全问题。

作为良好的习惯,在实现编辑数据的代码中,要调用ContentResolver.notifyChange()方法,通知那些监听数据变化的监听器。

在实现子类的时候,还有一些步骤可以简化Contentprovider客户端的使用:

定义public static final Uri常量,名称为CONTENT_URI:

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

如果有多个表,它们也是使用相同的CONTENT_URI,只是它们的路径部分不同。

也就是说红色框部分是一致的。

定义返回的列名,public static final,列名的值,比如使用SQLite数据库作为存储,对应表的列名。

在文档中要写出各个列的数据类型,便于使用者读取。

如果需要处理新的MIME数据类型,比如通过Intent的方式,并且带data的mimeType(参见总结一下Intent概念),那么需要在ContentProvider.getType()方法中进行处理,参见编写完整的Contentprovider示例编写一个getType方法部分。

如果处理数据库表中超大的数据,比如很大的位图文件,一般存在文件系统中,可以参照contentprovider中使用大型二进制文件,这样第三方的contentprovider使用者,可以访问不属于它权限的文件,通过contentprovider做代理。

声明 Content Provider

创建ContentProvider后,需要在manifest文件中声明,android系统才能知道它,当其他应用需要调用该ContentProvider时才能创建或者调用它。

语法类似:

<providerandroid:name="com.easymorse.cp.MyContentProvider"
            android:authorities="com.easymorse.cp.mycp"></provider>

android:name要写ContentProvider继承类的全名。

android:authorities要写和CONTENT_URI常量的B部分(见上面图)。

注意不要把上图C和D部分加到authorities中去。authorities是用来识别ContentProvider的,C和D部分实际上是ContentProvider内部使用的。

 

原文地址:https://www.cnblogs.com/zhuxuekui/p/3630541.html