zoukankan      html  css  js  c++  java
  • 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.4packagesprovidersContactsProvider。打开清单文件,能够看到例如以下信息:

     <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,记住别忘记加入读联系人和写联系人的权限。

    再打开srccomandroidproviderscontactsContactsProvider2.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;
    }

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

  • 相关阅读:
    DRUPAL-PSA-CORE-2014-005 && CVE-2014-3704 Drupal 7.31 SQL Injection Vulnerability /includes/database/database.inc Analysis
    WDCP(WDlinux Control Panel) mysql/add_user.php、mysql/add_db.php Authentication Loss
    Penetration Testing、Security Testing、Automation Testing
    Tomcat Server Configuration Automation Reinforcement
    Xcon2014 && Geekpwn2014
    phpMyadmin /scripts/setup.php Remote Code Injection && Execution CVE-2009-1151
    Linux System Log Collection、Log Integration、Log Analysis System Building Learning
    The Linux Process Principle,NameSpace, PID、TID、PGID、PPID、SID、TID、TTY
    Windows Management Instrumentation WMI Security Technology Learning
    IIS FTP Server Anonymous Writeable Reinforcement, WEBDAV Anonymous Writeable Reinforcement(undone)
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5284454.html
Copyright © 2011-2022 走看看