android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人
要使用一个ContentProvider,必须要知道的是它所能匹配的Uri及其数据存储的表的结构。
首先想办法找到访问短信及联系人数据的ContentProvider能接受的Uri:
到github上找对应ContentProvider的源码:https://github.com/android

有好多个,哪一个才是短信数据的ContentProvider呢?
在filters输入框:输入telephony。

现在只有一个了,打开:

装有git的话,可以选择clone到本地,没有的话,就选择下载zip包就行了。

进入src目录中,SmsProvider.java就是短信数据的ContentProvider了。查看源代码,搜索UriMatcher:
private static final UriMatcher sURLMatcher =
new UriMatcher(UriMatcher.NO_MATCH);
static {
sURLMatcher.addURI("sms", null, SMS_ALL);
sURLMatcher.addURI("sms", "#", SMS_ALL_ID);
sURLMatcher.addURI("sms", "inbox", SMS_INBOX);
sURLMatcher.addURI("sms", "inbox/#", SMS_INBOX_ID);
sURLMatcher.addURI("sms", "sent", SMS_SENT);
sURLMatcher.addURI("sms", "sent/#", SMS_SENT_ID);
sURLMatcher.addURI("sms", "draft", SMS_DRAFT);
sURLMatcher.addURI("sms", "draft/#", SMS_DRAFT_ID);
sURLMatcher.addURI("sms", "outbox", SMS_OUTBOX);
sURLMatcher.addURI("sms", "outbox/#", SMS_OUTBOX_ID);
可以看到跟之前自己定义ContentProvider的类似的静态代码块,其实是模仿它的源码写的。
从上面的addURI()方法,可以知道获取全部短信数据的URI就是:”content://sms”
这样,我们就可以访问到所有的短信内容了。
为了有短信给我们看,需要在模拟器上收发下短信:

在window->show view->other->找到Emulator Control,模拟110发送短信:
hello, you are wanted.
在模拟器中可以回复短信,现在模拟器中,有如下三条短信:

查看短信代码如下:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
Uri uri = Uri.parse("content://sms");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if(cursor == null){
return;
}
while(cursor.moveToNext()){
Log.i(TAG,cursor.getString(cursor.getColumnIndex("body")));
}
Log.i(TAG,cursor.getCount()+"");
}
要查看短信内容是需要权限的:
在Manifest.xml声明使用权限:
<uses-permission android:name="android.permission.READ_SMS"/>
运行结果:

可见,取出了短信的总数及每条短信的内容。
但是,怎样才能知道短信实际存储呢?
可以在File Explorer中,找到/data/data/com.android.providers.telephony/databases/mmssms.db,该数据库存放的就由短信的数据表,将其导出到电脑,可以用Sqlite Expert查看sms表:

可知,address字段为收件人或发件人号码,date为短信接收或发送的时间戳,type是短信的类型,1表示接收的短信,2表示发送的短信,body是短信的内容,所以,我们就可以根据这些个字段获取我们比较关心的信息了。
修改代码如下:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
Uri uri = Uri.parse("content://sms");
Cursor cursor = getContentResolver().query(uri, new String[]{"date","address","type","body"}, null, null, null);
if(cursor == null){
return;
}
while(cursor.moveToNext()){
Log.i(TAG,DateFormat.format("yyyy-MM-dd hh:mm", cursor.getLong(0)).toString());
Log.i(TAG,cursor.getInt(2) == 1 ? "收到":"发送给");
Log.i(TAG,cursor.getString(1)+"的短信:");
Log.i(TAG,cursor.getString(3));
}
Log.i(TAG,cursor.getCount()+"");
}
运行结果:

可以利用前面学习的解析XML的内容,将短信备份到XML文件中,这里就不再赘述了。
下面简单说明下使用ContentObserver监听短信的方法:
新建自己的ContentObserver:
class MyObserver extends ContentObserver{
public MyObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "您有新的短信,请注意查收", Toast.LENGTH_SHORT).show();
}
}
在MainActivity注册ContentObserver:
getContentResolver().registerContentObserver(uri, true, new MyObserver(new Handler()));
使用Emulator Controller向模拟器发送一条短信:

运行结果:

注意,在上面的uri后添加上inbox或者outbox可以观察收件箱及发件箱中的短信。在此,就不一一说明了。
查看联系人数据的ContentProvider的源码也可以从github上找到,在filters输入框中输入contacts即可:

打开,然后clone或者打包下载到本地
在src目录中找到:

ContactsProvider2.java,这个就是了。
搜寻addURI()方法,发现authority内容是:ContactsContract.AUTHORITY
在帮助手册中,查找ContactsContract类,可以找到其中定义的常量AUTHORITY的值为:”com.android.contacts”。
这样一来,就可以构造uri了。
在File Exploer中查看有关联系人数据的表结构:
为了让表中有数据,先添加几个联系人。
找到/data/data/com.android.providers.contacts/databases/contacts2.db
导出到电脑中,然后使用Sqlite Expert查看,发现有很多张表的。

重点关注raw_contacts、data、mimetypes这三张表。
添加联系人过程其实是先向raw_contacts添加一个id,然后把这个id连同该联系人数据中的某项数据作为一条记录插入到data表中,该联系人数据有多少项数据,就在data表中插入多少条数据。

如,我在模拟器中添加了两个联系人,每个联系人都添加了3项数据,分别为姓名、手机号和邮箱。则在raw_contacts中生成两条记录,id分别为1、2。然后在data表中生成了6条记录,每个联系人3条,都是在raw_contact_id和data1字段存入我所添加的数据内容。
所以,我们要获取联系人信息时,可以到data表中根据raw_contact_id分组进行获取每个联系人的所有信息。
注意到data表中有个字段名为mimetype_id存放的是每条记录中data1的类型,如1表示邮箱,7表示姓名等,可以查看mimetypes表:

Uri raw_uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri data_uri = Uri.parse("content://com.android.contacts/data");
注意,在通过data_uri获取信息时,若指定要查询的字段mimetype_id,会发现,找不到该字段。这是因为,这个ContentProvider内部帮我们做了表连接查询,我们查看的实际上是连接查询的视图,里面存放的是mimetype这个字段,而不再有mimetype_id字段。
修改MainActivity获取联系人信息:
Uri raw_uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri data_uri = Uri.parse("content://com.android.contacts/data");
Cursor raw_cursor = getContentResolver().query(raw_uri, new String[]{"_id"}, null, null, null);
if(raw_cursor == null){
return ;
}
Log.i(TAG,raw_cursor.getCount()+"");
while(raw_cursor.moveToNext()){
String id = raw_cursor.getString(0);
Cursor data_cursor = getContentResolver().query(data_uri, new String[]{"mimetype","data1"}, "raw_contact_id = ?", new String[]{id}, null);
if(data_cursor == null){
return ;
}
Log.i(TAG,"联系人"+id);
while(data_cursor.moveToNext()){
String type = data_cursor.getString(0);
if(type.equals("vnd.android.cursor.item/name")){
Log.i(TAG,"姓名:"+data_cursor.getString(1));
}else if(type.equals("vnd.android.cursor.item/phone_v2")){
Log.i(TAG,"手机号:"+data_cursor.getString(1));
}else if(type.equals("vnd.android.cursor.item/email_v2")){
Log.i(TAG,"邮箱:"+data_cursor.getString(1));
}
}
}
读取联系人信息是需要权限的:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
运行结果:

关于这两个ContentProvider还有其他的增删改操作这里就不一一说明,跟自己定义的ContentProvider的用法基本相同,只要懂得原理,到每个具体的ContentProvider基本上都是大同小异了。
android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人的更多相关文章
- Flutter学习笔记(36)--常用内置动画
如需转载,请注明出处:Flutter学习笔记(36)--常用内置动画 Flutter给我们提供了很多而且很好用的内置动画,这些动画仅仅需要简单的几行代码就可以实现一些不错的效果,Flutter的动画分 ...
- android 监听短信数据库,制作短信控制工具,控制别人的手机!!(一)
序言:本程序示例本着简洁易懂的目的,只做了简单的功能实现,需要用户启动应用,收到短信才有效果.作者将会在后面的(二)篇中加入服务后台运行.自动启动功能,实现一个真正的短信控制工具.本文的目的很简单,让 ...
- Android 监听短信(同时监听广播和数据库)
暗扣,强烈谴责这种侵害用户利益的行为... 下面给大家介绍Android暗扣原理....... Android4.4以下的系统玩游戏就要小心了哈 暗扣方式之一:短信订购,即监听--------拦截- ...
- Android手机上监听短信的两种方式
Android手机上监听短信有两种方式: 1. 接受系统的短信广播,操作短信内容. 优点:操作方便,适合简单的短信应用. 缺点:来信会在状态栏显示通知信息. AndroidManifest.xml: ...
- android菜鸟学习笔记21----ContentProvider(一)ContentProvider的简单使用
ContentProvider是Android四大组件之一,它用来封装数据,并通过ContentResolver接口将数据提供给其他应用.只有当需要在多个应用之间共享数据时才会用到ContentPro ...
- android菜鸟学习笔记14----Android控件(三) ListView的简单使用
MVC模式: MVC的基本原理就是通过Controller连接View和Model.当View中所显示的数据发生变化时,会通知Controller,然后由Controller调用Model中的相关方法 ...
- android菜鸟学习笔记19----Android数据存储(三)XML文件的解析及序列化
Android内置了PULL解析器的XPP3实现,以及SAX解析器等,可以直接使用PULL或SAX解析XML,直接把JAVA中进行PULL或SAX解析的代码直接拿来用,遗忘的话,可以参考java拾遗1 ...
- android菜鸟学习笔记20----Android数据存储(四))Android数据库操作
Android内置了一个名为SQLite的关系型数据库,这是一款轻量型的数据库,操作十分简便.SQLite与别的数据库不同的是,它没有数据类型.可以保存任何类型的数据到你所想要保存的任何表的任何列中. ...
- android菜鸟学习笔记29----Android应用向用户发送提示信息的方式总结
常见的向用户发送提示信息的方式有3种,分别为: 1)发送Toast信息 2)弹出对话框 3)发送通知 总结如下: 方式1:发送Toast信息: 这种方式最简单,在之前的学习中多次使用过.Toast是在 ...
随机推荐
- Java学习之泛型和异常
泛型 1,设计原则或目的:只要代码在编译的时候没有错误,就不会抛异常. 2,泛型通配符 :类型通配符一般是使用 ? 代替具体的类型实参.注意了,此处是类型实参,而不是类型形参!相当于(父类作用)L ...
- Python从2.7.5升级到3.6.5
Python从2.7.5升级到3.6.5学习了:https://blog.csdn.net/liang19890820/article/details/51079633 wget https://ww ...
- Laravel之中间件
一.中间件的作用 HTTP 中间件提供了一个便利的机制来过滤进入应用的 HTTP 请求.例如,Laravel 包含了一个中间件来验证用户是否经过授权,如果用户没有经过授权,中间件会将用户重定向到登录页 ...
- php装饰器
<?php /* * 用一个类来装饰另一个类,动态的给一个对象增加一些额外功能,这些功能一般是在这个对象调用方法前或方法后 * 比如我们要给User类增加一个登陆日志的功能 */ // 抽象构件 ...
- Linux下Nagios的安装与配置(转载)
一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等.在系统或服务状态异常时发出邮件或短信报 ...
- Android插件化开发,初入殿堂
好久没有写博客了,这次准备写写我这几天的研究成果--Android插件化开发框架CJFrameForAndroid. 好久没有写博客了,这次准备写写我这几天的研究成果--Android插件化开发框架C ...
- c#关于int(或其他类型)的字段在对象初始化时默认初始化问题的解决方法
问题: c#的wcf服务接口在后台通过自定义对象接收前台参数的时候,前台参数即使不传int类型的字段值,后台也会默认初始化为0,由于很多表示状态的int字段都是从0开始的,导致查询的时候有些不想参与查 ...
- ClassLibary和WPF User Control LIbary和WPF Custom Control Libary的异同
说来惭愧,接触WPF这么长时间了,今天在写自定义控件时遇到一个问题:运行界面中并没有显示自定义控件,经调试发现原来没有加载Themes中的Generic.xaml. 可是为什么在其他solution中 ...
- 高盛CEO致大学毕业生:要与有野心的人为伍
我认为讲的非常棒.年轻人就要这样. 高盛集团首席运行官(CEO)劳尔德-贝兰克梵(Lloyd Blankfein)周四在曼哈顿贾维茨中心參加了拉瓜迪亚社区大学的第41届毕业典礼并发表演讲.在面向约10 ...
- 使用spring-boot-admin对spring-boot服务进行监控(转自牛逼的人物)
尊重原创:http://www.cnblogs.com/ityouknow/p/8440455.html 上一篇文章<springboot(十九):使用Spring Boot Actuator监 ...