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:

 1 private static final UriMatcher sURLMatcher =
 2
 3             new UriMatcher(UriMatcher.NO_MATCH);
 4
 5
 6
 7     static {
 8
 9         sURLMatcher.addURI("sms", null, SMS_ALL);
10
11         sURLMatcher.addURI("sms", "#", SMS_ALL_ID);
12
13         sURLMatcher.addURI("sms", "inbox", SMS_INBOX);
14
15         sURLMatcher.addURI("sms", "inbox/#", SMS_INBOX_ID);
16
17         sURLMatcher.addURI("sms", "sent", SMS_SENT);
18
19         sURLMatcher.addURI("sms", "sent/#", SMS_SENT_ID);
20
21         sURLMatcher.addURI("sms", "draft", SMS_DRAFT);
22
23         sURLMatcher.addURI("sms", "draft/#", SMS_DRAFT_ID);
24
25         sURLMatcher.addURI("sms", "outbox", SMS_OUTBOX);
26
27         sURLMatcher.addURI("sms", "outbox/#", SMS_OUTBOX_ID);

可以看到跟之前自己定义ContentProvider的类似的静态代码块,其实是模仿它的源码写的。

从上面的addURI()方法,可以知道获取全部短信数据的URI就是:”content://sms”

这样,我们就可以访问到所有的短信内容了。

为了有短信给我们看,需要在模拟器上收发下短信:

在window->show view->other->找到Emulator Control,模拟110发送短信:

hello, you are wanted.

在模拟器中可以回复短信,现在模拟器中,有如下三条短信:

查看短信代码如下:

 1 protected void onCreate(Bundle savedInstanceState) {
 2
 3         super.onCreate(savedInstanceState);
 4
 5         setContentView(R.layout.main_layout);
 6
 7         Uri uri = Uri.parse("content://sms");
 8
 9         Cursor cursor = getContentResolver().query(uri, null, null, null, null);
10
11         if(cursor == null){
12
13               return;
14
15         }
16
17         while(cursor.moveToNext()){
18
19               Log.i(TAG,cursor.getString(cursor.getColumnIndex("body")));
20
21         }
22
23         Log.i(TAG,cursor.getCount()+"");
24
25 }

要查看短信内容是需要权限的:

在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是短信的内容,所以,我们就可以根据这些个字段获取我们比较关心的信息了。

修改代码如下:

 1 protected void onCreate(Bundle savedInstanceState) {
 2
 3         super.onCreate(savedInstanceState);
 4
 5
 6
 7         setContentView(R.layout.main_layout);
 8
 9         Uri uri = Uri.parse("content://sms");
10
11         Cursor cursor = getContentResolver().query(uri, new String[]{"date","address","type","body"}, null, null, null);
12
13         if(cursor == null){
14
15           return;
16
17         }
18
19         while(cursor.moveToNext()){
20
21           Log.i(TAG,DateFormat.format("yyyy-MM-dd hh:mm", cursor.getLong(0)).toString());
22
23           Log.i(TAG,cursor.getInt(2) == 1 ? "收到":"发送给");
24
25           Log.i(TAG,cursor.getString(1)+"的短信:");
26
27           Log.i(TAG,cursor.getString(3));
28
29         }
30
31         Log.i(TAG,cursor.getCount()+"");
32
33
34
35     }

运行结果:

可以利用前面学习的解析XML的内容,将短信备份到XML文件中,这里就不再赘述了。

下面简单说明下使用ContentObserver监听短信的方法:

新建自己的ContentObserver:

 1 class MyObserver extends ContentObserver{
 2
 3
 4
 5         public MyObserver(Handler handler) {
 6
 7              super(handler);
 8
 9         }
10
11
12
13         @Override
14
15         public void onChange(boolean selfChange) {
16
17              // TODO Auto-generated method stub
18
19              Toast.makeText(MainActivity.this, "您有新的短信,请注意查收", Toast.LENGTH_SHORT).show();
20
21         }
22
23 }

在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获取联系人信息:

 1 Uri raw_uri = Uri.parse("content://com.android.contacts/raw_contacts");
 2 Uri data_uri = Uri.parse("content://com.android.contacts/data");
 3         Cursor raw_cursor = getContentResolver().query(raw_uri, new String[]{"_id"}, null, null, null);
 4
 5
 6
 7         if(raw_cursor == null){
 8
 9               return ;
10
11         }
12
13         Log.i(TAG,raw_cursor.getCount()+"");
14
15         while(raw_cursor.moveToNext()){
16
17               String id = raw_cursor.getString(0);
18
19               Cursor data_cursor = getContentResolver().query(data_uri, new String[]{"mimetype","data1"}, "raw_contact_id = ?", new String[]{id}, null);
20
21               if(data_cursor == null){
22
23                   return ;
24
25             }
26
27               Log.i(TAG,"联系人"+id);
28
29               while(data_cursor.moveToNext()){
30
31                    String type = data_cursor.getString(0);
32
33                    if(type.equals("vnd.android.cursor.item/name")){
34
35                          Log.i(TAG,"姓名:"+data_cursor.getString(1));
36
37                    }else if(type.equals("vnd.android.cursor.item/phone_v2")){
38
39                          Log.i(TAG,"手机号:"+data_cursor.getString(1));
40
41                    }else if(type.equals("vnd.android.cursor.item/email_v2")){
42
43                          Log.i(TAG,"邮箱:"+data_cursor.getString(1));
44
45                    }
46
47               }
48
49  }

读取联系人信息是需要权限的:

<uses-permission android:name="android.permission.READ_CONTACTS"/>

运行结果:

关于这两个ContentProvider还有其他的增删改操作这里就不一一说明,跟自己定义的ContentProvider的用法基本相同,只要懂得原理,到每个具体的ContentProvider基本上都是大同小异了。

时间: 2024-08-08 05:19:39

android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人的相关文章

Android实战简易教程-第三十六枪(监听短信)

一般用户喜欢用手机号作为用户名注册APP账号,这时一般都是通过手机验证码的方式进行验证,下面我们就研究一个非常实用的方法,通过监听短信-实现短信验证码的自动填入,提高用户体验. 首先我们看一下如何监听手机短信. 一.获取短信全部内容 1.新建一个SMSBroadcastReceiver: <code class="hljs java has-numbering"><span class="hljs-keyword">package</s

Android实战简易教程-第三十六枪(监听短信-实现短信验证码自动填入)

一般用户喜欢用手机号作为用户名注册APP账号,这时一般都是通过手机验证码的方式进行验证,下面我们就研究一个非常实用的方法,通过监听短信-实现短信验证码的自动填入,提高用户体验. 首先我们看一下如何监听手机短信. 一.获取短信全部内容 1.新建一个SMSBroadcastReceiver: package com.example.messagecut; import java.text.SimpleDateFormat; import java.util.Date; import android.

(七)android开发中两种方式监听短信的原理和实现

一.监听短信的两种方式的简介 Android程序开发中,有两种方式监听短信内容:一.接收系统的短信广播:二.应用观察者模式,监听短信数据库. 第一种方式接收系统的短信广播: A.这种方式只对新收到的短消息有效,运行代码,并不会读取收件箱中已读或未读的消息,只有当收到新来的短消息时,才会执行onReceive()方法. B.并且这个广播是有序广播,如果当别的程序先读取到了这个广播,然后拦截掉了个这个广播,你将接收不到.当然我们可以通过设置priority的数值,其实有时是不管用的,现在在一些定制的

Android 监听短信2种方式:Broadcast和ContentObserver

1. 基于Broadcast接受短信 1.1 原理 Android收到短信后系统会发送一个android.provider.Telephony.SMS_RECEIVED广播.把它放在Bundle(intent.Extras)中,Bundle可以理解为一个Map,短信采用"pdus"作为键,pdus应该是protocol description units的简写,也就是一组短信.Android不是一接收到短信就立刻发出广播的,他会有一定的延迟,所以就有可能会有多条短信,所以才会用数组来存

Android 监听短信 两种方式

1. 接受系统的短信广播,操作短信内容. 优点:操作方便,适合简单的短信应用. 缺点:来信会在状态栏显示通知信息. AndroidManifest.xml: <uses-permission android:name="android.permission.SEND_SMS"></uses-permission> <uses-permission android:name="android.permission.RECEIVE_SMS"

Android 监听短信(同时监听广播和数据库)

暗扣,强烈谴责这种侵害用户利益的行为... 下面给大家介绍Android暗扣原理.......  Android4.4以下的系统玩游戏就要小心了哈 暗扣方式之一:短信订购,即监听--------拦截------------处理短信. 暗扣方式之二:模拟人为操作(又叫模拟流量),通过后台程序代码模拟人的点击行为,暗自给用户订购业务,由运营商收取你的费用,当然这其中也需要涉及监听/拦截/处理短信.使用这种方式的原理无非是Http处理网页,还涉及接入点切换问题,这里就不详细讲解. 回归正题:有的时候,

android菜鸟学习笔记21----ContentProvider(一)ContentProvider的简单使用

ContentProvider是Android四大组件之一,它用来封装数据,并通过ContentResolver接口将数据提供给其他应用.只有当需要在多个应用之间共享数据时才会用到ContentProvider. 多个应用共享数据时,如何区分是哪个应用中的那部分数据呢? ContentProvider通过Uri标识具体某个应用的某些数据.当一个应用提供了ContentProvider向其他应用共享数据时,该应用在其ContentProvider中添加标识自己特定数据的Uri,然后其他应用想要获得

android菜鸟学习笔记14----Android控件(三) ListView的简单使用

MVC模式: MVC的基本原理就是通过Controller连接View和Model.当View中所显示的数据发生变化时,会通知Controller,然后由Controller调用Model中的相关方法执行相应的数据修改操作.反之,当Model中的数据发生变化时,也会通知Controller,由Controller通知View更新显示内容.如此一来,就使得数据部分与视图部分相分离,任何一方发生改变都不会影响到另一方. 而在android中,MVC的一个常见应用就是ListView显示数据.V代表的

android菜鸟学习笔记19----Android数据存储(三)XML文件的解析及序列化

Android内置了PULL解析器的XPP3实现,以及SAX解析器等,可以直接使用PULL或SAX解析XML,直接把JAVA中进行PULL或SAX解析的代码直接拿来用,遗忘的话,可以参考java拾遗1,2,3关于XML的解析: 如有如下XmlUtils类实现PULL方式解析XML到List和序列化List到XML: Student实体类代码: 1 package cn.csc.bean; 2 3 public class Student { 4 5 private String id; 6 7