跨程序共享数据——Content Provider 之 ContentResolver基本用法 & 一个读取系统联系人的Demo
本模块共有四篇文章,参考郭神的《第一行代码》,对Content Provider的学习做一个详细的笔记,大家可以一起交流一下:
- 跨程序共享数据——Content Provider 之 运行时权限解析以及申请的实现(可完美解决java.lang.SecurityException:Permission Denial 问题)
- 跨程序共享数据——Content Provider 之 ContentResolver基本用法 & 一个读取系统联系人的Demo(即本文)
- 跨程序共享数据——Content Provider 之 创建自己的内容提供器
- Content Provider 之 最终弹 实战体验跨程序数据共享(结合SQLiteDemo)
内容提供器的用法一般有两种,
一种是使用现有的内容
提供器来读取和操作相应程序中的数据,
另一种是创建自己的
内容提供器给我们程序的数据提供外部访问接口。
那么接下来我们就一个一个开始学习吧,首先从使用现有的内容提供器
开始。
- 如果一个应用程序通过内容提供器对其数据提供了外部访问接口,那么任何其他的应用程序就都可以对这部分数据进行访问。
- Android系统中自带的电话簿、短信、媒体库等程序都提供了类似的访问接口,这就使得第三方应用程序可以充分地利用这部分数据来实现更好的功能。
下面我们就来看一看,内容提供器到底是如何使用的。
1.ContentResolver的基本用法
对于每一个应用程序来说,如果想要访问内容提供器中共享的数据,就一定要借助
Content-Resolver
类,可以通过Context中的getContentResolver()
方法获取到该类的实例。Content-Resolver中提供了一系列的方法用于对数据进行CRUD操作,
其中
insert()方法用于添加数据,
update()方法用于更新数据,
delete()方法用于删除数据,
query()方法用于查询数据。
有没有似曾相识的感觉?没错,SQLiteDatabase中也是使用这几个方法来进行CRUD操作的,只不过它们在方法参数上稍微有一些区别。
内容URI
不同于SQLiteDatabase,ContentResolver中的增删改查方法都是不接收表名参数的,而是使用一个Uri参数代替,这个参数被称为内容URI。内容URI给内容提供器中的数据建立了唯一标识符,它主要由两部分组成:authority和path。
authority
authority是用于对不同的应用程序做区分的,一般为了避免冲突,都会采用程序包名的方式来进行命名。比如某个程序的包名是com-example.app,那么该程序对应的authority就可以命名com.example.app.provider。
path
path则是用于对同一应用程序中不同的表做区分的,通常都会添加到authority的后面。比如某个程序的数据库里存在两张表:tablel和table2,这时就可以将path分别命名为/tablel和/tabIe2。
组合成内容URI
然后把authority和path进行组合,内容URI就变成了com.example.app.provider/table1和com-example.app.provider/table2。
不过,目前还很难辨认出这两个字符串就是两个内容URI,我们还需要在字符串的头部加上协议声明。因此,内容URI最标准的格式写法如下:
content://com.example.app.provider/table1
content://com.example.app.provider/table2
内容URI可以非常清楚地表达出我们想要访问哪个程序中哪张表里的数据。
也正是因此,ContentResoIver中的增删改查方法才都接收Uri对象作为参数,因为如果使用表名的话,系统将无法得知我们期望访问的是哪个应用程序里的表。
Uri.parse()解析URI字符串
在得到了内容URI字符串之后,我们还需要将它解析成Uri对象才可以作为参数传入。解析的方法也相当简单,代码如下所示:
Uri uri= Uri.parse("content://com.example.app.provider/tablel")
只需要调用Uri.parse()方法,就可以将内容URI字符串解析成Uri对象了。
现在我们就可以使用这个Uri对象来查询tablel表中的数据了,代码如下所示:
Cursor cursor =getContentResolver().query( uri, projection, selection, selectionArgs, sortOrder);
这些参数和SQLiteDatabase中query()方法里的参数很像,但总体来说要简单一些,毕竟这
是在访问其他程序中的数据,没必要构建过于复杂的查询语句。下表对使用到的这部分参数进行
了详细的解释。
遍历数据:
注意这里的moveToNext:第一次调用moveToNext的时候,默认就是移动到了第一行的游标位置,和调用moveToFirst的效果是一样的,但是第二次调用moveToNext的时候,游标就会向下移动了。
inert应用
可以看到,是将待添加的数据组装到ContentValues中,然后调用ContentResolver的insert()方法,将Uri和ContentValues作为参数传入即可。
update()应用
delete()应用
2.读取联系人
下面运用上面所学的知识,看看如何读取系统电话簿中的联系人信息。
现在在模拟器中手动添加几个联系人,以便稍后进行读取:
可以看到一开始电话簿里是没有任何联系人的,下面进行创建:
那个,联系人名字就,高傲牛肉方便面、中原一点红、香辣火腿肠,咳咳。。。
至此便可新建一个ContactsTest项目开始正式敲代码了。
首先编写一下布局文件,让读取出来的联系人信息显示在一个ListView中:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.contactstest.MainActivity"> <ListView android:id="@+id/contacts_view" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </LinearLayout>
MainActivity.java:
代码架构简析:
具体code:
public class MainActivity extends AppCompatActivity { ArrayAdapter<String> adapter; List<String> contactsList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //ListView实例化以及装载适配器 ListView contactsView = (ListView)findViewById(R.id.contacts_view); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,contactsList); contactsView.setAdapter(adapter); //申请权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission. READ_CONTACTS) != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this, new String[]{ Manifest. permission.READ_CONTACTS }, 1); }else{ readContacts(); } } //封装读通讯录的操作 private void readContacts(){ Cursor cursor = null; try{ //查询联系人数据 cursor = getContentResolver().query(ContactsContract.CommonDataKinds. Phone.CONTENT_URI, null, null, null, null); if(cursor != null){ while(cursor.moveToNext()){ //获取联系人姓名 String displayName = cursor.getString(cursor.getColumnIndex (ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); //获取联系人手机号 String number = cursor.getString(cursor.getColumnIndex (ContactsContract.CommonDataKinds.Phone.NUMBER)); //拼接数据,加入列表 contactsList.add(displayName + "\n" + number); } //通知刷新ListView adapter.notifyDataSetChanged(); } }catch(Exception e){ e.printStackTrace(); }finally { if(cursor != null){ cursor.close();//!!!!!!!!!!!!!!!!!!!!!!1及一定要关掉 } } } //权限申请的返回处理 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode){ case 1: if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ readContacts(); }else{ Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show(); } break; default: } } }
代码简析见注释,下面详解一下:
在onCreate()方法中,首先获取ListView的实例并给它设置适配器,
然后调用处理申请运行时权限,因为READ_CONTACTS权限是属于危险权限。
在用户授权之后调用readContacts()方法来读取系统联系人信息。
下面解析readContacts()方法:
首先是使用ContentResolver的query()方法来查询系统的联系人数据。
注意这里传入的Uri参数不是来自调用Uri.parse()方法解析的内容URI字符串,因为ContactsContract.CommonDataKinds.Phone类已经帮我们做好了封装,提供了一个CONTENT_URI常量,这个常量就是使用Uri.parse()方法解析出来的结果。
接着我们对Cursor对象进行遍历,将联系人姓名和手机号逐个取出,
联系人姓名这一列对应常量是ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
联系人手机号这一列对应的常量是ContactsContract.CommonDataKinds.Phone.NUMBER。
两列数据都取出后,将它们进行拼接并且在中间加上换行符,然后
将拼接后的数据add到ListView的数据源里,并通知刷新一下ListView。
最后记得将Cursor对象关闭掉。
最后声明读取系统联系人的权限。修改AndroidManifest.xmI:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
运行结果:

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
老司机带你快速上手调试Flutter项目
对于开发项目来说,调试控制工具是不可少的,开发者是一定要掌握调试工具的使用,一来是为了查看log日志,一来是为了排查错误,再一个原因是可以查看内存占用情况,以便后续性能优化。 Flutter的调试主要有3个需要去关注的,一个是Flutter Outline,一个是Flutter Inspector,还有一个是log控制台。前者主要是用于视图预览,后者是用于性能调试,log控制台用于查看log信息以及定位错误等。 下面就详细的讲解一下如何使用Flutter的调试工具。 一、基础配置和设置 在讲解调试工具之前,先来看看有关的设置选项,点击菜单栏File-->Settings-->Languages & Frameworks --> Flutter,打开之后设置如图2.6.1所示,重点字段我都翻译成了中文,帮助大家理解,如果不是很熟悉这个设置,推荐大家按照我这样去配置。 【提示】如果Flutter Outline和Flutter Inspector没有出现在侧边栏(默认是在右边侧边栏),建议重启Android Studio,如果还没有出现,建议卸载Flutter插件...
- 下一篇
react native ios打包 编译成功 Archive失败报错问题
报错问题如下: Invalid bitcode version (Producer: '902.0.39.1_0' Reader: '900.0.37_0')', using libLTO version 'LLVM version 9.0.0, (clang-900.0.37)' for architecture arm64 具体解决办法 image.png
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Hadoop3单机部署,实现最简伪集群
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16