利用ContentProvider读取系统应用的信息(短信和联系人)

上面两篇我们讲了ContentProvider如何使用

Android进阶:步骤2:ContentProvider初体验

https://blog.csdn.net/qq_17846019/article/details/83313922

Content Provider 解析URI的方法 UriMatcher的用法和自带的解析方法

https://blog.csdn.net/qq_17846019/article/details/83338284

1.现在我们将如何通过某一个应用读系统短消息

系统短信箱的Uri分成以下几个部分

  • content://sms 短信箱
  1. content://sms/inbox 收信箱
  2. content://sms/sent 发信箱
  3. content://sms/draft  草稿箱

可以跟你你想要拿的信箱加以区分

读取信箱分成以下三个步骤:

在内容处理者(ContentResolver)中处理

1.配置文件中添加读写信箱的权限,和android6.0后动态申请权限

2.获取内容处理者对象

3.查询方法返回Cursor对象

4.解析Cursor

代码:

AndroidManifest.xml中添加读信息的权限

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

android6.0后要动态申请权限

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private ContentResolver contentResolver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //1.申请权限 在配置文件中写还有动态申请
        checkPermission(this);
        //2拿的内容处理者对象
        contentResolver = getContentResolver();
        findViewById(R.id.sms_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //拿的发信箱的uri
                Uri uri = Uri.parse("content://sms/sent");
                //参数1:uri
                //参数2:查询指定列范围,null为查询所有
                //参数3:查询条件,不指定
                //参数4:查询条件数组,和参数2搭配使用,不指定
                //参数5:排序
                Cursor c = contentResolver.query(uri, null, null, null, null);
                //3.解析Uri
                //遍历Cursor
                while (c.moveToNext()) {
                    String msg = "";
//                    //显示每条发信箱的内容
//                    //遍历该行的列
//                    for(int i=0;i<c.getColumnCount();i++){
//                        msg+=c.getString(i)+" ";
//                    }
                    //如果只有拿接收者号码和信息内容
                    //系统指定的列名分别为 address body
                    String address = c.getString(c.getColumnIndex("address"));
                    String body = c.getString(c.getColumnIndex("body"));
                    msg = address + " " + body;
                    Log.e("TAG", "msg=" + msg);
                }
            }
        });
    }

    //android6.0之后要动态获取权限
    private void checkPermission(Activity activity) {
        // Storage Permissions
        final int REQUEST_EXTERNAL_STORAGE = 1;
        String[] PERMISSIONS_STORAGE = {
                Manifest.permission.READ_SMS,
        };

        try {
            //检测是否有读短信箱的权限
            int permission = ActivityCompat.checkSelfPermission(MainActivity.this,
                    "android.permission.READ_SMS");
            if (permission != PackageManager.PERMISSION_GRANTED) {
                // 没有读短信箱的权限,去申请写的权限,会弹出对话框
                ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Log打印结果:

这是我发信箱的短信

 

拿到的短信:

 E/TAG: msg=95559 66666
    msg=10086 ???

2.读取联系人

读取联系人和读取短信的类似

但稍微有点复杂,因为联系人的姓名和电话号码是放在不同的两个表的,需要进行两次查询

联系人姓名是主表,id是主键,电话号码所在的表是从表,可以通过主表的id主键来查到对应从表的电话号码

步骤:

1.添加权限

2.查询操作,返回Cursor

3.解析Cursor

代码:

1.添加权限

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

6.0后动态申请权限写在一起了后面就不写了 

    //android6.0之后要动态获取权限
    private void checkPermission(Activity activity) {
        // Storage Permissions
        final int REQUEST_EXTERNAL_STORAGE = 1;
        String[] PERMISSIONS_STORAGE = {
                Manifest.permission.READ_SMS,
                Manifest.permission.READ_CONTACTS,
                Manifest.permission.WRITE_CONTACTS
        };

        try {
            //检测是否有读短信箱的权限
            int permission = ActivityCompat.checkSelfPermission(MainActivity.this,
                    "android.permission.READ_SMS");
           //检查是否有读联系人的权限
            int permission2 = ActivityCompat.checkSelfPermission(MainActivity.this,
                    "android.permission.READ_CONTACTS");
            //检查是否有写联系人的权限
            int permission3 = ActivityCompat.checkSelfPermission(MainActivity.this,
                    "android.permission.WRITE_CONTACTS");
            if (permission != PackageManager.PERMISSION_GRANTED ||
                permission2!= PackageManager.PERMISSION_GRANTED ||
                    permission3 != PackageManager.PERMISSION_GRANTED) {
                // 没有某一个权限,去申请相应权限,会弹出对话框
                ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    findViewById(R.id.read_contact_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //对应联系人而言,他们的存储方式是将姓名和其他内容(电话号码)由不同的ContentProvider操作的
                //首先想象联系人和其他内容属于不同的表
                //而姓名所在的表示主表,其他内容位于从表
                //而主表的主键id在从表中作为外键使用
                //1.查姓名的uri
                Uri uri1 = ContactsContract.Contacts.CONTENT_URI;
                Cursor c1 = contentResolver.query(uri1, null, null, null, null);
                while (c1.moveToNext()) {
                    //姓名的列
//                ContactsContract.Contacts.DISPLAY_NAME;
//                //主键id的列
//                ContactsContract.Contacts._ID;
                    //同样可以遍历所有列,但这里只要看姓名和电话
                    String name = c1.getString(c1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                    String id = c1.getString(c1.getColumnIndex(ContactsContract.Contacts._ID));

                    //继续访问下一个Uri拿到对应从表的电话号码
                    //2.查找电话的Uri
                    Uri uri2 = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
                    //在从表外键id的查询条件
                    String selection = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?";
                    //通过这个外键找到相应的电话号码
                    Cursor c2 = contentResolver.query(uri2,
                            null,
                            selection,//查询条件
                            new String[]{id},//查询条件的值
                            null);
                    //每一id(一个人)都可以有多个电话号码
                    //还有要将每个电话号码拿出来
                    while (c2.moveToNext()) {
                        //取出电话号码的列
                        String number = c2.getString(c2.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                        name += " 电话:" + number;
                    }
                    Log.e("TAG", "姓名是:" + name + " id是:" + id);
                }
            }
        });

输出结果:

E/TAG: 姓名是:Cmcc 电话:1 387-891-2345 id是:1
E/TAG: 姓名是:Love 电话:1 827-891-2345 电话:1 527-891-2345 id是:2

如果仅仅查询某个人的电话

更改一个查询的语句,添加上查询条件

Cursor c1 = contentResolver.query(
uri1,
null, 
ContactsContract.Contacts.DISPLAY_NAME+"=?",//查询条件
 new String[]{"Love"},//查询条件值数组
 null);

就会只显示Love的电话

E/TAG: 姓名是:Love 电话:1 827-891-2345 电话:1 527-891-2345 id是:2

 3.添加联系人

上面权限的就不写了,在上一个获取联系人

  findViewById(R.id.add_contact_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //1.往一个ContentProvider中插入一条空数据,获取新的id
                //2.利用刚刚生成的id分别组合姓名和电话号码往另一个ContentProvider插入数据
                ContentValues values=new ContentValues();
                //拿到插入空数据的uri
                Uri uri=ContactsContract.RawContacts.CONTENT_URI;
                //返回的uri后面追加有id
                Uri returnUri=contentResolver.insert(uri,values);
                //获取这个id
                long id= ContentUris.parseId(returnUri);

                //插入姓名
                //获取插入姓名的Uri
                Uri nameUri=ContactsContract.Data.CONTENT_URI;
                //放姓名的列名
                values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,"新联系人");
                //放id的列名
                values.put(ContactsContract.Data.RAW_CONTACT_ID,id);
                //指定添加的添加的数据类型(在ContentProvider 有一个获取类型的方法)
                values.put(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
                contentResolver.insert(nameUri,values);

                //插入电话号码
                //先清空之前的数据
                values.clear();
                //插电话号码
                values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,"13878999999");
                //放id的列名
                values.put(ContactsContract.Data.RAW_CONTACT_ID,id);
                //指定数据类型
                values.put(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
                //对于电话号码,可能是手机号或者是座机号码
                //所以要指定电话号码的类型是移动电话
                values.put(ContactsContract.CommonDataKinds.Phone.TYPE,ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
                contentResolver.insert(ContactsContract.Data.CONTENT_URI,values);
            }
        });

效果演示 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值