zoukankan      html  css  js  c++  java
  • 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基本上都是大同小异了。

  • 相关阅读:
    WORD2003电子签名插件(支持手写、签章)
    苹果App部署HTTPS进行在线下载安装
    解决安卓SDK更新连不通问题
    部署rfc5766-turn-server--谷歌推荐的开源穿透服务器 [复制链接]
    实测可用的免费STUN服务器!
    seajs加载jquery时提示$ is not a function该怎么解决
    tomcat发布web service教程
    Java WebService 简单实例
    HTML 5 断点续上传
    MySQL said: Authentication plugin 'caching_sha2_password' cannot be loaded
  • 原文地址:https://www.cnblogs.com/dqrcsc/p/4640718.html
Copyright © 2011-2022 走看看