Android基础笔记(十四)- 内容提供者读取联系人

简介:

利用内容提供者读取联系人

读取联系人相对于读取短信来说就复杂非常多了,我们一步一步来吧。

先看看一下联系人的数据库,是位于什么地方!


既然非常复杂,我们就一步步分析吧,我们把contacts2.db导出到电脑中,并使用SQLite数据库软件打开。

你能够看到一大堆的表和视图,当然我们使用到的也仅仅有三张。各自是raw_contactsdatamimetypes分别存储着联系人ID、联系人数据、联系人数据相应的MIMIE类型。

我们逐个看一下,首先是raw_contacts表。 
 
在本表的contact_id列存储的是手机中联系人所相应的ID。通过上面的图能够知道,在手机中有两个联系人。


接下来看一下data表。


 
在本表中。我们最关心的有三列mimetype_idraw_contact_iddata1。当中mimetype_idmimetype表的主键ID;相应的raw_contact_id就是raw_contactcontact_id列了。

那么data1列代表的什么呢?

你猜的不错,就是我们联系人的数据。横向来看,raw_contact_id同样的行中data1列数据组成了一个联系人的数据。

在看一下mimetypes表的情况吧。 
 
也是比較简单。不同的mimetype内容代表的不同数据类型。比方:电话号、姓名、Email等。

看起来非常麻烦的样子,貌似还须要讲data表和mimetypes表联合查询才干够。

可是实际上不用这么麻烦,Google工程师已经为我们准备了view_data的视图,已经将datamimetypes两张表的数据联结起来了。

我们赶紧看看里面的内容吧。


 
了解视图结构后,我们通过contact_id查询一下,就能够得到数据的内容和内容类型了。

分析完联系人的表,接下来就是怎样使用内容解析者去查询了,跟之前一样。依然要知道主机名路径

跟着我一起看一下源代码,这次联系人应用内容提供者的路径为android4.4\packages\providers\ContactsProvider。打开清单文件,能够看到例如以下信息:

 <provider android:name="ContactsProvider2"
    android:authorities="contacts;com.android.contacts"
    android:label="@string/provider_label"
    android:multiprocess="false"
    android:exported="true"
    android:readPermission="android.permission.READ_CONTACTS"
    android:writePermission="android.permission.WRITE_CONTACTS">
</provider>

主机名是:com.andriod.contacts,记住别忘记加入读联系人和写联系人的权限。

再打开src\com\android\providers\contacts\ContactsProvider2.java文件,看一下路径是什么。

static {
    // Contacts URI matching table
     matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
     matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);
    ... ...

     matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
     matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);
     ... ...
}

能够得知,查看raw_contacts的路径就是raw_contacts,查看data表的路径就是data

该准备的东西都准备完成了。那么就进入到代码的步骤吧。
① 在raw_contacts表中查询出来联系人的ID集合
② 以联系人ID为过滤条件,在view_data视图中,查找mimetype和data1

下面是代码:

// 在raw_contacts表中查询出来联系人的ID集合
Uri rawContactsUri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri viewDataUri = Uri.parse("content://com.android.contacts/data");

Cursor rawContactsCursor = getContentResolver().query(rawContactsUri, null, null, null, null);
if (rawContactsCursor != null) {

    while (rawContactsCursor.moveToNext()) {
        int columnIndex = rawContactsCursor.getColumnIndex("contact_id");
        String contact_id = rawContactsCursor.getString(columnIndex);
        // System.out.println("联系人ID:" + contact_id);

        // 以联系人ID为过滤条件。在view_data视图中,查找mimetype和data1

        Cursor viewDataCursor = getContentResolver().query(viewDataUri, new String[] { "mimetype", "data1" }, "contact_id=?", new String[] { contact_id }, null);

        if (viewDataCursor != null) {

            while (viewDataCursor.moveToNext()) {
                String mimetype = viewDataCursor.getString(0);
                String data1 = viewDataCursor.getString(1);

                if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
                    System.out.println("联系人ID:" + contact_id + ",电话:" + data1);
                } else if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {
                    System.out.println("联系人ID:" + contact_id + ",email:" + data1);
                } else if ("vnd.android.cursor.item/name".equals(mimetype)) {
                    System.out.println("联系人ID:" + contact_id + ",联系人姓名:" + data1);
                }

            }

            viewDataCursor.close();
        }

    }

    rawContactsCursor.close();
}

利用内容提供者插入联系人

插入联系人分为下面几步:
①手动插入联系人ID;ID值为数据库中总条目数加1。
②再依次向 data表中插入联系人数据。

总体的代码还是比較清晰地,请看下吧:

String name = et_name.getText().toString().trim();
String phone = et_phone.getText().toString().trim();

int contact_id = 0;

Uri rawContactsUri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri viewDataUri = Uri.parse("content://com.android.contacts/data");

// 手动插入联系人ID;ID值为数据库中总条目数加1。
Cursor rawContactsCursor = getContentResolver().query(rawContactsUri, null, null, null, null);
if (rawContactsCursor != null) {
    int count = rawContactsCursor.getCount();
    contact_id = count + 1;
    rawContactsCursor.close();
}
// 插入联系人ID
ContentValues values = new ContentValues();
values.put("contact_id", contact_id);
getContentResolver().insert(rawContactsUri, values);

// 再依次向`data`表中插入联系人数据。
ContentValues nameValues = new ContentValues();
nameValues.put("raw_contact_id", contact_id);
nameValues.put("mimetype", "vnd.android.cursor.item/name");
nameValues.put("data1", name);
getContentResolver().insert(viewDataUri, nameValues);

ContentValues phoneValues = new ContentValues();
phoneValues.put("raw_contact_id", contact_id);
phoneValues.put("mimetype", "vnd.android.cursor.item/phone_v2");
phoneValues.put("data1", phone);
getContentResolver().insert(viewDataUri, phoneValues);

以上都是演示样例代码,假设要实际使用还须要做非常多非常多工作。

内容观察者的原理

ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理。它相似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时。便会触发它。

使用ContentObserver的情况主要有一下两者情况:
①须要频繁检測的数据库或者某个数据是否发生改变,假设使用线程去操作。非常不经济并且非常耗时 。
②在用户不知晓的情况下对数据库做一些事件。比方:悄悄发送信息、拒绝接受短信黑名单等;

利用内容观察者监听系统应用数据库或者自己应用数据库的变化

这里就给出一个简单的样例吧。博主的学识还是太浅了,刚才浏览了网上一些人写的内容观察者的博客,认为自己会的东西还是太少了。小小总结一下。

当以后用到的时候再细致的总结。

使用观察者监听系统应用的变化

监听数据库的变化,主要使用到了ContentResler类中的registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)方法。

第一个參数是我们监视的Uri。第二个參数为true时会匹配全部以我们指定的Uri开头的地址,第三个參数就是我们的观察者了。

假设我们要监听系统短信数据库的变化,能够这么做:

Uri uri = Uri.parse("content://sms");
getContentResolver().registerContentObserver(uri, true, new ContentObserver(new Handler()) {
    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        System.out.println("短信内容发生改变了");
    }
});

已经知道了怎样监视一个Uri的变化后,监听我们自己应用数据库的变化,仅仅须要将Uri改动一下就能够了。可是,这里还差一步。当我们通过内容提供者去訪问已有数据后,还要通知一下,这样才干够让观察者接收到内容改变的消息。

这里就使用到了ContentReslover中的notifyChange(Uri uri, ContentObserver observer)方法。

// 提供给外部应用调用的查询方法
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    int MATCH_CODE = MURI_MATCHER.match(uri);
    if (MATCH_CODE == QUERY_SUCCESS) {
        // 大喊一声,数据发生改变了
        getContext().getContentResolver().notifyChange(uri, null);
        return db.query(ACCOUNT, projection, selection, selectionArgs, null, null, sortOrder);
    }
    return null;
}

这两篇博客写的比較仓促,请多多包括了。





本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5284454.html,如需转载请自行联系原作者

相关文章
|
11月前
|
Web App开发 安全 程序员
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
多年的互联网寒冬在今年尤为凛冽,坚守安卓开发愈发不易。面对是否转行或学习新技术的迷茫,安卓程序员可从三个方向进阶:1)钻研谷歌新技术,如Kotlin、Flutter、Jetpack等;2)拓展新功能应用,掌握Socket、OpenGL、WebRTC等专业领域技能;3)结合其他行业,如汽车、游戏、安全等,拓宽职业道路。这三个方向各有学习难度和保饭碗指数,助你在安卓开发领域持续成长。
187 1
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
|
11月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
357 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
JavaScript 前端开发 Java
FFmpeg开发笔记(四十七)寒冬下安卓程序员的几个技术转型发展方向
IT寒冬使APP开发门槛提升,安卓程序员需转型。选项包括:深化Android开发,跟进Google新技术如Kotlin、Jetpack、Flutter及Compose;研究Android底层框架,掌握AOSP;转型Java后端开发,学习Spring Boot等框架;拓展大前端技能,掌握JavaScript、Node.js、Vue.js及特定框架如微信小程序、HarmonyOS;或转向C/C++底层开发,通过音视频项目如FFmpeg积累经验。每条路径都有相应的书籍和技术栈推荐,助你顺利过渡。
266 3
FFmpeg开发笔记(四十七)寒冬下安卓程序员的几个技术转型发展方向
|
编解码 安全 Ubuntu
Android Selinux 问题处理笔记
这篇文章是关于处理Android系统中SELinux权限问题的笔记,介绍了如何通过分析SELinux拒绝的日志、修改SELinux策略文件,并重新编译部署来解决权限问题,同时提供了一些SELinux的背景知识和实用工具。
806 0
|
安全 Linux Android开发
FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库
该文介绍了如何在Linux服务器上交叉编译Android的FFmpeg库以支持HTTPS视频播放。首先,从GitHub下载openssl源码,解压后通过编译脚本`build_openssl.sh`生成64位静态库。接着,更新环境变量加载openssl,并编辑FFmpeg配置脚本`config_ffmpeg_openssl.sh`启用openssl支持。然后,编译安装FFmpeg。最后,将编译好的库文件导入App工程的相应目录,修改视频链接为HTTPS,App即可播放HTTPS在线视频。
302 3
FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库
|
安全 数据库 Android开发
45. 【Android教程】内容提供者 - Content Provider
45. 【Android教程】内容提供者 - Content Provider
220 2
|
Java 测试技术 开发工具
Android 笔记:AndroidTrain , Lint , build(1),只需一篇文章吃透Android多线程技术
Android 笔记:AndroidTrain , Lint , build(1),只需一篇文章吃透Android多线程技术
|
设计模式 缓存 前端开发
真的强!借助阿里技术博主分享的Android面试笔记,我拿到了字节跳动的offer
真的强!借助阿里技术博主分享的Android面试笔记,我拿到了字节跳动的offer
|
Java API Android开发
技术经验分享:Android源码笔记——Camera系统架构
技术经验分享:Android源码笔记——Camera系统架构
175 0
|
存储 Java API
Android系统 文件访问权限笔记
Android系统 文件访问权限笔记
1407 1