Android查缺补漏--ContentProvider的使用
ContentProvider (内容提供者)是一种共享型组件,可以为系统内应用于与应用之间提供访问接口。
ContentProvide要想正常工作需要三个关键点:
- ContentProvider:对外提供数据的访问接口。
- Uri:ContentProvider的唯一标识,外界可根据其访问对应的ContentProvider。
- ContentResolver
比如,当应用A想把自己数据暴露出来让别的应用也可以操作的话,就可以在应用A内部创建一个ContentProvider实现相关方法并添加URI,然后在其他应用中(应用B)就可以通过ContentResolver和URI来访问应用A中的ContentProvider了。
很多人都会觉得ContentProvider很难理解,因为很多书上在介绍ContentProvider是后上来就用很复杂的方式来讲解,还结合什么数据库、xml等等之类操作,搞得看起来很复杂,让很多的初学者望而却步,其实我们完全不必害怕。你可以把ContentProvider看做是一个网站,在生活中你想访问一个网站就必须要有一个URL地址,而这里的URI就好比这个URL地址,然后就可以用ContentResolver拿着这个这个URI地址去访问了。
一、创建自己的ContentProvider
- 创建ContentProvider。
创建一个自己的ContentProvider也很简单,同四大组件中其他的组件类似,首先继承系统ContentProvider来创建一个类,并实现相关方法:
public class UserInfoProvider extends ContentProvider {
static final String TAG = UserInfoProvider.class.getSimpleName();
@Override
public boolean onCreate() {
Log.i(TAG, "onCreate: ");
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
Log.i(TAG, "query: ");
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
Log.i(TAG, "getType: ");
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
Log.i(TAG, "insert: ");
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
Log.i(TAG, "delete: ");
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
Log.i(TAG, "update: ");
return 0;
}
}
然后再 AndroidMainfest.xml 中注册并添加 authorities,这个authorities就是传入到URI中用的,注意要将exported设为true这样外界才能访问到。
<provider
android:name=".contentprovides.UserInfoProvider"
android:authorities="cn.codingblock.androidadvancestudy.contentprovides.UserInfoProvider"
android:exported="true" />
一个基本的ContentProvider创建好了,接下来要做的就是使用ContentResolver来访问它了。
- 解析Uri
解析Uri使用Uri.parse()来解析,传入对应的参数,参数格式为:
content://authorities/ 对应于上面的UserInfoProvider来说,一个URI为:
Uri uri = Uri.parse("content://cn.codingblock.androidadvancestudy.contentprovides.UserInfoProvider/");
- 通过Context.getContentResolver()获取ContentResolver对象。
ContentResolver contentResolver = getContentResolver();
我们另外新建一个工程,暂且叫做TestApp吧,在这个新的工程里面添加一个Activity,在Activity中使用ContentResolver,通过URI来访问上面的(不同应用中)ContentProvider。
public class UserInfoResolverActivity extends AppCompatActivity implements View.OnClickListener {
private final static String TAG = UserInfoResolverActivity.class.getSimpleName();
private ContentResolver contentResolver;
private Uri uri = Uri.parse("content://cn.codingblock.androidadvancestudy.contentprovides.UserInfoProvider/");
Button btn_insert;
Button btn_query;
Button btn_update;
Button btn_delete;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_info_resolver);
// 获取ContentResolver对象
contentResolver = getContentResolver();
btn_insert = (Button) findViewById(R.id.btn_insert);
btn_query = (Button) findViewById(R.id.btn_query);
btn_update = (Button) findViewById(R.id.btn_update);
btn_delete = (Button) findViewById(R.id.btn_delete);
btn_insert.setOnClickListener(this);
btn_query.setOnClickListener(this);
btn_update.setOnClickListener(this);
btn_delete.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_insert:
insert();
break;
case R.id.btn_query:
query();
break;
case R.id.btn_update:
update();
break;
case R.id.btn_delete:
delete();
break;
}
}
public void insert() {
Uri tempUri = contentResolver.insert(uri, values);
Log.i(TAG, "insert: tempUri = " + tempUri);
}
public void query() {
Cursor cursor = contentResolver.query(uri, null, "where", null, null);
Log.i(TAG, "query: cursor = " + cursor);
}
public void update() {
int n = contentResolver.update(uri, values, "where", null);
Log.i(TAG, "update: n = " + n);
}
public void delete() {
int n = contentResolver.delete(uri, "where", null);
Log.i(TAG, "delete: n = " + n);
}
}
需要注意一点是,这个UserInfoProvider和UserInfoResolverActivity并没有在同一个应用中,UserInfoProvider在AndroidAdvanceStudy这个应用里面,他的进程名是:cn.codingblock.androidadvancestudy。UserInfoResolverActivity在TestApp应用里面,进程名是:cn.codingblock.testapp。
在testApp点击以上的增、查、改、删按钮,log如下:
12-12 15:06:26.846 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: insert:
12-12 15:06:28.070 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: query:
12-12 15:06:29.733 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: update:
12-12 15:06:30.376 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: delete:
看,我们是在TestApp应用中做的相关操作,果然可以调用AndroidAdvanceStudy里面的UserInfoProvider。
ContenProvider就是这么简单,当然 ContentProvider 的功能远不止如此,我们也可以结合数据库或者SharePreference等实现更加复杂的对外数据操作。
二、调用系统的ContentProvider
除了我们自己创建ContentProvider,Android系统也给我们提供了丰富的ContentProvider接口,这里就以操作系统的联系人为例来说明一下怎使用系统提供的ContentProvider接口。
- ContactsContract.Contacts.CONTENT_URI:联系人Uri。
- ContactsContract.CommonDataKinds.Phone.CONTENT_URI:联系人电话号码Uri。
1、查询系统联系人
通过系统联系人的Uri获取系统联系人及手机号码:
public void query() {
showContact = "";
// 获取联系人的Cursor集合
Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
while (cursor.moveToNext()) {
// 获取联系人id
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
// 获取联系人姓名
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
// 获取当前联系人id下的所有电话号码
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id, null, null);
showContact += "--id="+ id + " | name=" + name + "--\n";
Log.i(TAG, "onCreate: ------id="+ id + " | name=" + name + "------");
while (phones.moveToNext()) {
String phone = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
showContact += "phone = " + phone + "\n";
Log.i(TAG, "onCreate: phone = " + phone);
}
phones.close();
}
cursor.close();
tv_show.setText(showContact);
}
查询后log如下:
12-13 17:19:49.490 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=1 | name=张飞------
12-13 17:19:49.490 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 151 1511 1511
12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=2 | name=关羽------
12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 6969 3869
12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 135 6497 8664
12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 155 5555 5555
12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 133 3333 3333
12-13 17:19:49.508 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=3 | name=刘备------
12-13 17:19:49.508 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 156 9637 5648
12-13 17:19:49.508 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 7564 8643
12-13 17:19:49.520 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=14 | name=吕布------
12-13 17:19:49.520 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15678909087
12-13 17:19:49.529 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=20 | name=孙权------
12-13 17:19:49.529 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366669999
12-13 17:19:49.538 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=21 | name=曹操------
12-13 17:19:49.538 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15699788966
12-13 17:19:49.547 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=22 | name=马超------
12-13 17:19:49.547 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366999966
2、添加系统联系人:
public void insert() {
String name = et_name.getText().toString();
String phone = et_phone.getText().toString();
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(phone)) {
Toast.makeText(getApplicationContext(), "不能为空", Toast.LENGTH_LONG).show();
return;
}
ContentValues values = new ContentValues();
// 往插入一个空值以便获取id
Uri rawContactUri = getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, values);
long rawContactId = ContentUris.parseId(rawContactUri);
// ------插入联系人姓名------
// 设置id
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
// 设置内容类型
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
// 设置名字
values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name);
// 插入姓名
getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
values.clear();
// ------插入联系人电话------
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);
values.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
Toast.makeText(getApplicationContext(), "添加成功", Toast.LENGTH_LONG).show();
query();
}
在输入框中输入联系人姓名(诸葛亮)及电话号码(13696969696),然后点击添加按钮,log如下:
12-13 17:23:37.577 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=1 | name=张飞------
12-13 17:23:37.577 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 151 1511 1511
12-13 17:23:37.589 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=2 | name=关羽------
12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 6969 3869
12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 135 6497 8664
12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 155 5555 5555
12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 133 3333 3333
12-13 17:23:37.603 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=3 | name=刘备------
12-13 17:23:37.603 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 156 9637 5648
12-13 17:23:37.603 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 7564 8643
12-13 17:23:37.616 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=14 | name=吕布------
12-13 17:23:37.617 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15678909087
12-13 17:23:37.630 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=20 | name=孙权------
12-13 17:23:37.630 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366669999
12-13 17:23:37.657 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=21 | name=曹操------
12-13 17:23:37.657 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15699788966
12-13 17:23:37.671 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=22 | name=马超------
12-13 17:23:37.671 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366999966
12-13 17:23:37.712 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=23 | name=诸葛亮------
12-13 17:23:37.712 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 13696969696
可以看到,诸葛亮和电话号码已经被成功添加进去了。
当然,除了以上几个Uri,系统的ContentProvider接口还有很多很多,就不一一举例了,用到时可以查询官方API。
最后想说的是,本系列文章为博主对Android知识进行再次梳理,查缺补漏的学习过程,一方面是对自己遗忘的东西加以复习重新掌握,另一方面相信在重新学习的过程中定会有巨大的新收获,如果你也有跟我同样的想法,不妨关注我一起学习,互相探讨,共同进步!
参考文献:
- 《Android开发艺术探索》
- 《Android开发进阶从小工到专家》
Android查缺补漏--ContentProvider的使用的更多相关文章
- Android查缺补漏(IPC篇)-- Bundle、文件共享、ContentProvider、Messenger四种进程间通讯介绍
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8387752.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(IPC篇)-- 进程间通讯基础知识热身
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8479282.html 在Android中进程间通信是比较难的一部分,同时又非常 ...
- Android查缺补漏(IPC篇)-- 款进程通讯之AIDL详解
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(IPC篇)-- 进程间通讯之Socket简介及示例
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8425736.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(IPC篇)-- 进程间通讯之AIDL详解
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(View篇)--自定义 View 的基本流程
View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以 ...
- Android查缺补漏(View篇)--事件分发机制源码分析
在上一篇博文中分析了事件分发的流程及规则,本篇会从源码的角度更进一步理解事件分发机制的原理,如果对事件分发规则还不太清楚的童鞋,建议先看一下上一篇博文 <Android查缺补漏(View篇)-- ...
- Android查缺补漏(线程篇)-- IntentService的源码浅析
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8975114.html 在Android中有两个比较容易弄混的概念,Servic ...
- Android查缺补漏--Activity生命周期和启动模式
一.生命周期 onCreate():启动Activity时,首次创建Activity时回调. onRestart():再次启动Activity时回调. onStart():首次启动Activity时在 ...
随机推荐
- [转载] redis-cluster研究和使用
转载自http://hot66hot.iteye.com/blog/2050676 最近研究redis-cluster,正好搭建了一个环境,遇到了很多坑,系统的总结下,等到redis3 release ...
- UTF-8和UTF-8无BOM,一个会导致文件中中文变量无法匹配的bug
昨晚用dom4j中的selectSingleNode解析xml,匹配节点. 发现匹配不到,但是确实存在该节点 将regex改为regex1后则可以匹配,也就是说文件中的"阿里旺旺" ...
- 弄明白python reduce 函数
作者:Panda Fang 出处:http://www.cnblogs.com/lonkiss/p/understanding-python-reduce-function.html 原创文章,转载请 ...
- 理解defineProperty以及getter、setter
我们常听说vue是用getter与setter实现数据监控的,那么getter与setter到底是什么东西,它与defineProperty是什么关系,平时有哪些用处呢?本文将为大家一一道来. 对象的 ...
- 中介者模式(Mediator)
中介者模式(Mediator) 中介者模式也是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改.如果使用中介者模式,只 ...
- 矩阵取数游戏洛谷p1005
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...
- centos 下安装pptp (vpn) 的方法
废话少说 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 3 ...
- 在Linux中使用线程
我并不假定你会使用Linux的线程,所以在这里就简单的介绍一下.如果你之前有过多线程方面的编程经验,完全可以忽略本文的内容,因为它非常的初级. 首先说明一下,在Linux编写多线程程序需要包含头文件p ...
- javascript设计模式——发布订阅模式
前面的话 发布—订阅模式又叫观察者模式,它定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在javascript开发中,一般用事件模型来替代传统的发布—订阅模 ...
- DXGI快速截屏录屏技术
DXGI快速截屏录屏技术 概述 很多地方都需要用到截屏/录屏技术,比如桌面直播,桌面录制等等.在微软Windows平台,有很多截屏的接口,不过大多数性能并不理想,Windows8以后微软引入了一套 ...