Android四大组件之ContentProvider总结
来源:互联网 发布:身份证录入软件 编辑:程序博客网 时间:2024/06/04 18:29
ContentProvider
ContentProvider,顾名思义,内容提供者,为存储和获取数据提供统一的接口,可以在不同的应用程序之间共享数据。
ContentProvider为应用间的数据交互提供了一个安全的环境。它准许你把自己的应用数据根据需求开放给其他应用进行增、删、改、查,而不用担心直接开放数据库权限而带来的安全问题。
ContentProvider提供了对底层数据存储方式的抽象,如下图中:
底层使用了SQLite数据库,在用了ContentProvider封装后,即使你把数据库换成MongoDB,也不会对上层数据使用层代码产生影响。
ContentResolver
ContentProvider对数据层进行了封装,那该如何使用ContentProvider进行增,删,改,查的操作呢?
在一个应用中直接调用另一个应用的ContentProvider,显然是不可能的。Android中跨进程,一定需要通过Binder机制。
其实系统就提供给了我们一个叫ContentResolver的东西。ContentResolver,顾名思义,内容解析者。
我们可以在Context的实现类ContextImpl中获得ApplicationContentResolver的实例,ApplicationContentResolver继承自ContentResolver(ContentResolver是个抽象类):
private final ApplicationContentResolver mContentResolver; @Override public ContentResolver getContentResolver() { return mContentResolver; } private static final class ApplicationContentResolver extends ContentResolver { …… }
之后ContentResolver通过层层调用,与系统服务进行交互,最后成功调用ContentProvider。情况可以分为三种:
Provider进程不存在:当Provider进程不存在时,先创建进程并发布对应的Provider。
Provider未发布:请求Provider时,Provider进程存在但Provider的记录对象为空,则要去发布对应的Provider。
Provider已发布:直接可以调用了。
关于源码的解析,请移步大神Gityuan写的理解ContentProvider原理。
ContentResolver帮助我们统一管理与不同ContentProvider间的操作,如图:
ContentProvider中的URI
那ContentResolver是如何找到自己需要的ContentProvider呢?我们通过URI(Uniform Resource Identifier),即一个标识、定位任何资源的字符串。
ContentProvider中的URI有固定格式,如下图:
- Authority:授权信息,用以区别不同的ContentProvider
- Path:表名,用以区分ContentProvider中不同的数据表
- Id:Id号,用以区别表中的不同数据
URI组装代码示例:
public class TestContract { protected static final String CONTENT_AUTHORITY = "me.pengtao.contentprovidertest"; protected static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); protected static final String PATH_TEST = "test"; public static final class TestEntry implements BaseColumns { public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_TEST).build(); protected static Uri buildUri(long id) { return ContentUris.withAppendedId(CONTENT_URI, id); } protected static final String TABLE_NAME = "test"; public static final String COLUMN_NAME = "name"; }}
从上面代码我们可以看到,我们创建了一个content://me.pengtao.contentprovidertest/test
的uri,并且开了一个静态方法,用以在有新数据产生时根据id生成新的uri。
创建ContentProvider
必须方法
抽象类ContentProvider定义了六个抽象方法,您必须将这些方法作为自己具体子类的一部分加以实现。 所有这些方法(onCreate() 除外)都由一个尝试访问您的内容提供程序的客户端应用调用:
query():
从您的提供程序检索数据。使用参数选择要查询的表、要返回的行和列以及结果的排序顺序。 将数据作为 Cursor 对象返回。
insert():
在您的提供程序中插入一个新行。使用参数选择目标表并获取要使用的列值。 返回新插入行的内容 URI。
update():
更新您提供程序中的现有行。使用参数选择要更新的表和行,并获取更新后的列值。 返回已更新的行数。
delete():
从您的提供程序中删除行。使用参数选择要删除的表和行。 返回已删除的行数。
getType():
返回内容 URI 对应的 MIME 类型。实现内容提供程序 MIME 类型部分对此方法做了更详尽的描述。
onCreate():
初始化您的提供程序。Android 系统会在创建您的提供程序后立即调用此方法。 请注意,ContentResolver 对象尝试访问您的提供程序时,系统才会创建它。
注意:
所有这些方法(onCreate() 除外)都可由多个线程同时调用,因此它们必须是线程安全方法。
避免在 onCreate() 中执行长时间操作。将初始化任务推迟到实际需要时进行。
尽管您必须实现这些方法,但您的代码只需返回要求的数据类型,无需执行任何其他操作。 例如,您可能想防止其他应用向某些表插入数据。 要实现此目的,您可以忽略 insert() 调用并返回 0。
UriMatcher
为帮助您选择对传入的内容 URI 执行的操作,提供程序 API 加入了实用类 UriMatcher,它会将内容 URI“模式”映射到整型值。您可以在一个 switch 语句中使用这些整型值,为匹配特定模式的一个或多个内容 URI 选择所需操作。
例1:
content://com.example.app.provider/table1
一个名为 table1 的表
例2:
content://com.example.app.provider/table3/1
对应由 table3 中 1 标识的行的内容 URI
例3:
以下代码段演示了 UriMatcher 中方法的工作方式。 此代码采用不同方式处理整个表的 URI 与单个行的 URI,它为表使用的内容 URI 模式是 content://< authority >/< path >
,为单个行使用的内容 URI 模式则是 content://< authority >/< path >/< id >
。
方法addURI()会将授权和路径映射到一个整型值,方法match()会返回URI的整型值。switch语句会在查询整个表与查询单个记录之间进行选择:
public class ExampleProvider extends ContentProvider {... // Creates a UriMatcher object. private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { /* * The calls to addURI() go here, for all of the content URI patterns that the provider * should recognize. For this snippet, only the calls for table 3 are shown. */ /* * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used * in the path */ sUriMatcher.addURI("com.example.app.provider", "table3", 1); /* * Sets the code for a single row to 2. In this case, the "#" wildcard is * used. "content://com.example.app.provider/table3/3" matches, but * "content://com.example.app.provider/table3 doesn't. */ sUriMatcher.addURI("com.example.app.provider", "table3/#", 2); }... // Implements ContentProvider.query() public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {... /* * Choose the table to query and a sort order based on the code returned for the incoming * URI. Here, too, only the statements for table 3 are shown. */ switch (sUriMatcher.match(uri)) { // If the incoming URI was for all of table3 case 1: if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC"; break; // If the incoming URI was for a single row case 2: /* * Because this URI was for a single row, the _ID value part is * present. Get the last path segment from the URI; this is the _ID value. * Then, append the value to the WHERE clause for the query */ selection = selection + "_ID = " uri.getLastPathSegment(); break; default: ... // If the URI is not recognized, you should do some error handling here. } // call the code to actually do the query }
程序权限
即使底层数据为私有数据,所有应用仍可从您的提供程序读取数据或向其写入数据,因为在默认情况下,您的提供程序未设置权限。 要想改变这种情况,请使用属性或 < provider > 元素的子元素在您的清单文件中为您的提供程序设置权限。 您可以设置适用于整个提供程序、特定表甚至特定记录的权限,或者设置同时适用于这三者的权限。
您可以通过清单文件中的一个或多个 < permission > 元素为您的提供程序定义权限。要使权限对您的提供程序具有唯一性,请为 android:name 属性使用 Java 风格作用域。 例如,将读取权限命名为 com.example.app.provider.permission.READ_PROVIDER
。
更多权限设置,请见谷歌官方文档——创建内容提供程序。
参考:
1.ContentProvider从入门到精通
2.谷歌官方文档——创建内容提供程序
3.理解ContentProvider原理
- Android的四大组件之ContentProvider总结
- Android的四大组件之ContentProvider总结
- Android的四大组件之ContentProvider总结
- android四大组件之ContentProvider个人总结
- Android四大组件之四:ContentProvider总结
- Android的四大组件之ContentProvider总结
- Android四大组件之ContentProvider总结
- Android四大组件之ContentProvider
- android四大组件之ContentProvider
- android四大组件之 ContentProvider
- Android四大组件之ContentProvider
- Android四大组件之ContentProvider
- android 四大组件之ContentProvider
- Android四大组件之ContentProvider
- Android四大组件之ContentProvider
- android四大组件之ContentProvider
- android四大组件之ContentProvider
- Android四大组件之ContentProvider
- 用户产生内容(ugc)让页面内容信息丰富化
- 消息队列的流派之争
- 非递归求二叉树的深度
- UI设计讲座:UI/UX设计师如何提升自己,月薪6千与2万的差别
- h5腾讯提供的边栏垂直滚动导航案例
- Android四大组件之ContentProvider总结
- 微信支付 java后端
- input框进行搜索遇到bug解决思路小感
- 学习之路——用可重用的链表模块来实现命令行菜单小程序V2.5
- SSM项目 JSP页面中超链接含中文文件名,无法下载的问题解决
- com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException
- [C++] MD5加密算法原理及实现
- Android用代码给TextView中间部分设置不同的颜色
- 基于CentOS搭建Discuz