Android-ContentProvider详解及实例
Posted 帅次
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android-ContentProvider详解及实例相关的知识,希望对你有一定的参考价值。
好问的人,只做了五分钟的愚人;耻于发问的人,终身为愚人。
android提供了5种方式来存储数据。
咱们今天就来学习一下ContentProvider。作为Android四大巨头之一的他有点名不副实,因为在一般的开发过程中,使用的次数比较少。大部分应用的数据缓存用SharedPreferences就能搞定了。
ContentProvider(数据提供者)是应用程序之间共享数据的一种接口机制,是一种更为高级的数据共享方法。
ContentProvider可以指定需要共享的数据,而其他应用程序则可以在不知道数据来源、路径的情况下,对共享数据进行增删改查等操作。
在Android系统中,许多Android系统内置的数据也是通过ContentProvider提供给用户使用,例如通讯录、音视频文件和图像文件等。
1.什么是ContentProvider
ContentProvider是Android的四大组件之一,以标准化的方式在Android 应用间共享数据。
ContentProvider封装的数据存储以及增删改查等,并且必须实现一个对外统一的接口(Uri)。
2.什么是Uri
Uri(通用资源标识符 Universal Resource Identifer),代表数据操作的地址,每一个ContentProvider都会有唯一的地址。
ContentProvider使用的Uri语法结构如下:
content://authority/data_path/id
content://是通用前缀,表示该UIR用于ContentProvider定位资源。
authority是授权者名称,用来确定具体由哪一个ContentProvider提供资源。因此一般authority都由类的小写全称组成,以保证唯一性。
data_path是数据路径,用来确定请求的是哪个数据集。
id是数据编号,用来请求单条数据。如果是多条这个字段忽略。
样例:
content://com.scc.userprovider/user多条
content://com.scc.userprovider/user/10单条
3.什么是ContentResolver
ContentResolver是数据调用者,ContentProvider将数据发布出来,通过ContentResolver对象结合Uri进行调用。
一般来说ContentProvider是单例模式,多个应用可通过ContentResolver调用ContentProvider的增删改查操作数据,ContentResolver调用的数据操作会让同一个ContentProvider处理。
4.创建ContentProvider
1.创建一个类让其继承ContentProvider,并重载6个函数
需要实现的主要方法是:
insert()、delete()、update()、query():用于对数据集的增删改查操作。
onCreate():一般用来初始化底层数据集和建立数据连接等工作
getType():用来返回指定Uri的MIME数据类型,
若Uri是单条数据,则返回的MIME数据类型以vnd.Android.cursor.item开头;
若Uri是多条数据,则返回的MIME数据类型以vnd.android.cursor.dir/开头。
数据访问方法(例如insert(Uri,ContentValues)和update(Uri,ContentValues,Bundle))可以同时从多个线程调用,并且必须是线程安全的。其他方法(如onCreate())仅从应用程序主线程调用,并且必须避免执行冗长的操作。请参阅其预期线程行为的方法描述。
2.声明Uri规则,实现UriMatcher
咱先来看看UriMatcher是干嘛的,UriMatcher本质上是一个文本过滤器,有助于解析Uri,用在ContentProvider中帮助我们过滤,分辨出查询者想要查询哪个数据表。
UriMatcher的构造函数中,UriMatcher.NO_MATCH是Uri无匹配时的返回代码,值为-1。 addUri() 方法用来添加新的匹配项,语法为:
public void addUri(String authority, String path, int code)
其中authority表示匹配的授权者名称,path表示数据路径,code表示返回代码。下面咱来个样例:
//这里的名称必须与AndroidManifest.xml中android:authorities保持一致
public static final String AUTHORITY = "com.scc.userprovider";
//数据路径
public static final String PATH_USERS = "user";
//访问ContentProvider的URL
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + PATH_USERS);
//返回代码
public static final int USER_INFO = 1;
//创建UriMatcher对象
private static UriMatcher uriMatcher;
//创建静态代码块
static {
//实例化UriMatcher对象
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//参数1:authority;参数2:路径;参数3:自定义代码
uriMatcher.addURI(UserInfoContent.AUTHORITY, UserInfoContent.PATH_USERS, USER_INFO);
}
3.注册ContentProvider
在AndroidManifest.xml文件中的 application节点下使用标签注册。样例:
<android:authorities="com.scc.userprovider"
android:name=".UserProvider"
android:exported="true"/>
android:name指定ContentProvider实现的类名
android:authorities指定ContentProvider对应Uri(相当于ContentProvider分配一个域名)
android:exported指定ContentProvider是否允许其他应用调用。如果将该属性设置为true,则允许其他应用调用
5.使用ContentProvider
1.添加数据
通过insert()函数添加单条数据:
ContentValues cv = new ContentValues();
cv.put(UserInfoContent._ID, bean.get_id());
cv.put(UserInfoContent.USER_NAME, bean.getName());
cv.put(UserInfoContent.USER_AGE, bean.getAge());
cv.put(UserInfoContent.USER_UPDATE_TIME, bean.getUpdate_time());
Uri uri = getContentResolver().insert(UserInfoContent.CONTENT_URI, cv);
Log.e(getClass().getName(), "insert:" + uri);
通过bulkInsert()函数添加多条数据:
ContentValues[] arrayValues = new ContentValues[10];
//实例化每一个ContentValues...
int count = getContentResolver().bulkInsert(UserInfoContent.CONTENT_URI, arrayValues);
2.删除操作
指定ID删除单条数据
int delete = getContentResolver().delete(UserInfoContent.CONTENT_URI, "_id=12", null);
Log.e(getClass().getName(), "delete(失败返回-1):" + delete);
通过selection语句删除多条数据
String selection = UserInfoContent._ID + ">12";
int result = getContentResolver().delete(UserInfoContent.CONTENT_URI, selection, null);
3.更新操作
UserInfoBean bean = new UserInfoBean("蚩尤", 32, "12:00");
ContentValues cv = new ContentValues();
cv.put(UserInfoContent.USER_NAME, bean.getName());
cv.put(UserInfoContent.USER_AGE, bean.getAge());
cv.put(UserInfoContent.USER_UPDATE_TIME, bean.getUpdate_time());
getContentResolver().update(UserInfoContent.CONTENT_URI, cv, "_id=18", null);
4.查询操作
Cursor cursor = getContentResolver().query(UserInfoContent.CONTENT_URI, null, selection, null, null);
//循环取出游标指向的每条用户记录
while (cursor.moveToNext()) {
UserInfoBean user = new UserInfoBean();
user.name = cursor.getString(cursor.getColumnIndex(UserInfoContent.USER_NAME));
user.age = cursor.getInt(cursor.getColumnIndex(UserInfoContent.USER_AGE));
user._id = cursor.getString(cursor.getColumnIndex(UserInfoContent._ID));
user.update_time = cursor.getString(cursor.getColumnIndex(UserInfoContent.USER_UPDATE_TIME));
userList.add(user); //添加到用户信息列表
}
cursor.close(); //关闭数据库游标
Log.e(getClass().getName(), "Query用户:" + String.format("当前共找到%d个用户", userList.size()));
6.其他应用使用ContentProvider
跟5.本应用使用ContentProvider一样的方法,这边就不做复制了,5的Uri是拼接字段,但是拼接后的结果content://com.scc.userprovider/user。
6的第一个参数:Uri uricontent = Uri.parse("content://com.scc.userprovider/user");
1.新增数据+查找数据
2.修改数据+删除数据
7.java.lang.SecurityException: Permission Denial: opening provider com.scc.cp.UserProvider from ProcessRecord
解决方案:在AndroidManifest.xml文件中的 application节点下使用标签注册时android:exported="false"时,不允许其他应用调用。所以其他和应用使用ContentProvider会崩溃报错。将exported改为:android:exported="true"即可。
源码:ContentProviderDemo.zip
以上是关于Android-ContentProvider详解及实例的主要内容,如果未能解决你的问题,请参考以下文章
Android-ContentProvider简单的增删改查
搜索引擎系列六:Lucene搜索详解(Lucene搜索流程详解搜索核心API详解基本查询详解QueryParser详解)