Android 四大组件 (三) ContentProvider 使用简介

来源:互联网 发布:大众软件2016 7月 编辑:程序博客网 时间:2024/06/05 12:41

  在日常的开发中,对ContentProvider的接触比较少,总体的认识就是一个用于提供分享信息的渠道(可以是应用内部也可以是不同的App之间),它们通过唯一的uri进行通信。因为使用的不是特别多,所以这里也只是简单介绍一下ContentProvider的使用。主要有下面几点:

1. 创建自己的ContentProvider对外部提供数据;

2. 使用ContentResolver获取外部App提供的数据;

3. 操作系统的联系人;


相关知识简介

  Uri(Uniform Resource Identifier) 统一资源标识符

  在ContentProvider中Uri代表了要操作的数据的路径,有了Uri,系统就知道这个Uri对应的数据由哪个ContentProvider提供

  一般格式:content:// authority/标识(可选)


  UriMatcher类

  在使用Uri的时候你需要将Uri对应到具体对某个数据库的某种操作上去,UriMatcher类就是Android提供用于将Uri跟code(自定义的常量)对应起来的一个类,有了UriMatcher就     可以轻松地对应Uri跟code,然后根据不同的code执行不同的操作。


  Cursor类

  数据库游标,可以通过moveToNext等方法遍历元素。


一、创建ContentProvider对外提供服务

  这里使用对外提供联系人表为例(这里省略了具体的数据库表操作,因为我们主要是为了讲ContentProvider,我们只是简单地进行了Log操作证明别的应用调用到了数据库操作的部分)。

  创建ContentProvider的Authority(一般为包名,要保证Authority在系统中的唯一性!),这个Authority就是Uri中的authority;

private static final String AUTHORITY = "com.scut.jayme";

上面代码确定Authority为包名。


  新建一个ContentProvider类(这里就叫ContactProvider)

  ContactProvider要继承自ContentProvider并且实现其中的虚函数。

package com.scut.jayme;import android.content.ContentProvider;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.net.Uri;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.util.Log;/** * 提供数据的示例 * 对外部提供用户的联系人表 * * Created by jayme on 15/12/19. */public class ContactProvider extends ContentProvider {    private static final String AUTHORITY = "com.scut.jayme";    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);    public static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);    public static final int USER_CONTACT = 0;    public static final int USER_CONTACT_ID = 1;    /**     * 这里使用静态初始化块是为了让 sUriMatcher 及时得到初始化     */    static {        /** UriMatcher可以将uri跟code建立关联,也可以把一个uri转化为一个code,code是自定义的用于区分操作的int变量 */        sUriMatcher.addURI(AUTHORITY, "contact", USER_CONTACT);        sUriMatcher.addURI(AUTHORITY, "contact/#", USER_CONTACT_ID); //#代表一个具体的数值    }    private static final String TAG = "contact";    private static final String MIME_TYPE_ITEM = "com.scut.jayme.item/contact";    private static final String MIME_TYPE_DIR = "com.scut.jayme.dir/contact";    @Override    public boolean onCreate() {        return true;    }    @Nullable    @Override    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {        Log.i(TAG, "查询 contact表");        /** 这里讲具体的Uri转换为code */        int operationCode = sUriMatcher.match(uri);        switch (operationCode){            case USER_CONTACT:                Log.i(TAG, "查询到了 contact表");                break;            case USER_CONTACT_ID:                int id = Integer.parseInt(uri.getPathSegments().get(1));                Log.i(TAG, "查询到了 contact表, id = " + id);                break;                        default: Log.i(TAG, "Invalid request: " + uri);        }        return null;    }    @Nullable    @Override    public String getType(@NonNull Uri uri) {        try {            Integer.parseInt(uri.getPathSegments().get(1));            return MIME_TYPE_ITEM;        } catch (NumberFormatException ex) {            return MIME_TYPE_DIR;        }    }    @Nullable    @Override    public Uri insert(@NonNull Uri uri, ContentValues values) {        /** 这里讲具体的Uri转换为code */        int operationCode = sUriMatcher.match(uri);        switch (operationCode) {            case USER_CONTACT:                Log.d(TAG, "成功在 contact表 中插入一条数据");                //Todo 执行插入数据库操作                break;            default:                Log.e(TAG, "Invalid request: " + uri);        }        return null;    }    @Override    public int delete(@NonNull Uri uri, String where, String[] selectionArgs) {        /** 这里讲具体的Uri转换为code */        int operationCode = sUriMatcher.match(uri);        //Todo 执行删除数据库操作        switch (operationCode) {            case USER_CONTACT:                if (where == null) {                    Log.d(TAG, "删除 contact表 中的所有元素");                } else {                    Log.d(TAG, "删除 contact表 重元素, where = " + where);                }                break;            case USER_CONTACT_ID:                int id = Integer.parseInt(uri.getPathSegments().get(1));                Log.d(TAG, "删除 contact表 中元素, id = " + id);                break;                        default:                Log.e(TAG, "Invalid request: " + uri);        }        return 1;    }    @Override    public int update(@NonNull Uri uri, ContentValues values, String where, String[] selectionArgs) {        /** 这里讲具体的Uri转换为code */        int operationCode = sUriMatcher.match(uri);        //Todo 执行更新数据库操作        switch (operationCode) {            case USER_CONTACT:                if (where == null) {                    Log.e(TAG, "更新失败");                } else {                    Log.d(TAG, "更新成功, where = " + where);                }                break;            case USER_CONTACT_ID:                int id = Integer.parseInt(uri.getPathSegments().get(1));                Log.d(TAG, "更新成功, id = " + id);                break;                        default:                 Log.e(TAG, "Invalid request: " + uri);        }        return 1;    }}

代码中的注释解释了一些操作的原因,这样我们就已经写好了一个ContentProvider


在AndroidMainfest.xml文件中配置Provider

<!-- 允许外部访问的话要加上exported = true -->        <provider            android:authorities="com.scut.jayme"            android:name="com.scut.jayme.ContactProvider"            android:exported="true" >        </provider>

把上面这段代码加入到application下就可以了。


二、使用ContentResolver获取数据

要获取数据有两部,第一步是知道提供数据ContentProvider的Uri,然后就是从Activity中调用getContentResolver获取到一个ContentResolver对象,然后就可以对数据进行处理了,具体可以仔细看代码中的注释。

package com.jayme.aboutcontentresolver;import android.app.Activity;import android.content.ContentValues;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;/** * 测试ContentResolver操作别的App提供的数据 *  * Created by Jayme on 16/01/23 */public class MainActivity extends Activity {    /** 数据来源的Uri */    public static final Uri CONTACT_URI            = Uri.parse("content://com.scut.jayme/contact");        public static final Uri CONTACT_ITEM_URI            = Uri.parse("content://com.scut.jayme/contact/1");    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        /**         * 查询 CONTACT表         * 返回一个Cursor对象即可获取到表中数据         * Todo: 利用返回的Cursor对象获取数据         */        Cursor cursor = getContentResolver().query(CONTACT_URI, null, null, null, null);        /**         * 往 CONTACT表中插入一条数据         * ContentValues是一个保存键值对的对像         * 因为是在测试,所以values也是随便写的,记得要传一个ContentValues对象即可         */        ContentValues values = new ContentValues(1);        values.put("name", "Jayme");        getContentResolver().insert(CONTACT_URI, values);        /**         * 删除 CONTACT表 中id为1的项         */        getContentResolver().delete(CONTACT_ITEM_URI, null, null);        /**         * 更新 CONTACT表中id为1的项         */        getContentResolver().update(CONTACT_ITEM_URI, values, null, null);    }}

如果你先运行了利用ContentProvider提供数据的App,然后再运行利用使用ContentResolver使用数据的App,你就可以在提供数据App的控制台中看到相应的输出,记住,一定要先启动提供数据的App。


三、操作Android提供的联系人表

Demo截图



获取所有联系人的信息

首先需要获取到一个ContentResolver对象,这里现在onCreate中获取到了(也就是说把下面那句代码放到onCreate里)

mContentResolver = getContentResolver();

然后利用上面的Uri查询获得一个Cursor对象就可以获取到所有联系人的信息,这里展示方式为在Log中显示。

先获取到联系人的id跟name,然后再通过联系人的id进行了一次查询操作获取到了联系人的号码(因为号码可能有多个, 所以需要遍历),切记不要传错Uri!!!

    /**     * 显示所有手机联系人     */    private void showContacts(){        Cursor cursor = mContentResolver.query(Contacts.CONTENT_URI, null, null, null, null);        /** 这里遍历可以获取到所有联系人的 id 跟 name */        while(cursor != null && cursor.moveToNext()){            String id = cursor.getString(cursor.getColumnIndex(Contacts._ID));            String name = cursor.getString(cursor.getColumnIndex(Contacts.DISPLAY_NAME));            /** 再进行一次查询获取对应联系人的电话号码 */            Cursor phoneCursor = mContentResolver.query(Phone.CONTENT_URI, null, Phone.CONTACT_ID + "=" + id, null, null);            StringBuilder sb = new StringBuilder("contact_id = ").append(id).append(" " + name);            while(phoneCursor != null && phoneCursor.moveToNext()){                sb.append(" " + phoneCursor.getString(phoneCursor.getColumnIndex(Phone.NUMBER)));            }            /** 关闭Cursor对象 */            if(null != phoneCursor){                phoneCursor.close();            }            /** 显示信息 */            Log.i(TAG, sb.toString());        }        /** 关闭Cursor对象 */        if(null != cursor){            cursor.close();        }    }

在联系人中插入一条数据

  插入一条联系人的记录有两步,首先要通过RawContacts的Uri生成一条联系人纪录,然后再通过Data的Uri对刚刚生成记录进行信息的修改(依据RawContacts生成记录的Id)

    /**     * 增加一条数据     */    private void addContact(String name, String phone){        /** 先新建一条联系人数据并获取它对应的Id */        ContentValues values = new ContentValues();        Uri newContactUri = mContentResolver.insert(RawContacts.CONTENT_URI, values);        long contactId = ContentUris.parseId(newContactUri);        /** 添加不同信息使用的是同一个Uri,具体操作的区分是通过 MIMETYPE 来区别的 */                /** 添加刚才新建联系人的姓名 */        values.put(Data.RAW_CONTACT_ID, contactId);        values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);        values.put(StructuredName.GIVEN_NAME, name);        mContentResolver.insert(Data.CONTENT_URI, values);        values.clear();        /** 添加刚才新建联系人的电话 */        values.put(Data.RAW_CONTACT_ID, contactId);        values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);        values.put(Phone.NUMBER, phone);        values.put(Phone.TYPE, Phone.TYPE_MOBILE);        mContentResolver.insert(Data.CONTENT_URI, values);        values.clear();        /** 添加刚才新建联系人的邮箱 */        values.put(Data.RAW_CONTACT_ID, contactId);        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);        values.put(Email.DATA, "liujiescut@163.com");        values.put(Email.TYPE, Email.TYPE_WORK);        mContentResolver.insert(Data.CONTENT_URI, values);    }

查询电话对应的联系人

    /**     * 查找电话对应联系人     * @param phoneNumber 对应电话     */    private void queryContact(String phoneNumber){        Uri uri = Uri.parse(Phone.CONTENT_URI + "/filter/" + phoneNumber);        Cursor cursor = mContentResolver.query(uri, new String[]{ContactsContract.Data.DISPLAY_NAME}, null, null, null);        if(null != cursor && cursor.moveToFirst()){            showToast("电话 " + phoneNumber + " 对应联系人是 " + cursor.getString(0));        }else{            showToast("没有找到对应的联系人");        }        if(null != cursor){            cursor.close();        }    }

删除对应姓名的联系人

    /**     * 删除对应姓名的联系人     * @param name 联系人姓名     */    private void deleteContact(String name){        Cursor cursor = mContentResolver.query(RawContacts.CONTENT_URI, new String[]{ContactsContract.Data._ID}, "display_name=?", new String[]{name}, null);        if(null != cursor && cursor.moveToFirst()){            //获取联系人对应Id            int id = cursor.getInt(0);                        //根据id删除data中的相应数据            mContentResolver.delete(RawContacts.CONTENT_URI, "display_name=?", new String[]{name});            mContentResolver.delete(Data.CONTENT_URI, "raw_contact_id=?", new String[]{id + ""});            showToast("delete " + name + " success");        }    }


最后贴出完整的MainActivity.java代码

package com.jayme.contacts;import android.app.Activity;import android.content.ContentResolver;import android.content.ContentUris;import android.content.ContentValues;import android.database.Cursor;import android.net.Uri;import android.provider.ContactsContract;import android.provider.ContactsContract.Contacts;import android.provider.ContactsContract.Data;import android.provider.ContactsContract.RawContacts;import android.provider.ContactsContract.CommonDataKinds.Phone;import android.provider.ContactsContract.CommonDataKinds.Email;import android.provider.ContactsContract.CommonDataKinds.StructuredName;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;public class MainActivity extends Activity implements View.OnClickListener{    private static final String TAG = "tag_contacts";        private ContentResolver mContentResolver;    private Button mShowContactsButton;    private Button mInsertButton;    private Button mQueryButton;    private Button mDeleteButton;    private EditText mInsertNameEditText;    private EditText mInsertPhoneEditText;    private EditText mQueryNameEditText;    private EditText mDeleteNameEditText;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mContentResolver = getContentResolver();        findViews();        initListeners();    }    /**     * 绑定控件     */    private void findViews(){        mShowContactsButton = (Button) findViewById(R.id.main_btn_show_contacts);        mInsertButton = (Button) findViewById(R.id.main_btn_add);        mDeleteButton = (Button) findViewById(R.id.main_btn_delete);        mQueryButton = (Button) findViewById(R.id.main_btn_query);        mInsertNameEditText = (EditText) findViewById(R.id.main_et_add_name);        mInsertPhoneEditText = (EditText) findViewById(R.id.main_et_add_phone);        mQueryNameEditText = (EditText) findViewById(R.id.main_et_query_phone);        mDeleteNameEditText = (EditText) findViewById(R.id.main_et_delete_name);    }    /**     * 为按钮设置监听     */    private void initListeners(){        mShowContactsButton.setOnClickListener(this);        mDeleteButton.setOnClickListener(this);        mInsertButton.setOnClickListener(this);        mQueryButton.setOnClickListener(this);    }        /**     * 显示所有手机联系人     */    private void showContacts(){        Cursor cursor = mContentResolver.query(Contacts.CONTENT_URI, null, null, null, null);        /** 这里遍历可以获取到所有联系人的 id 跟 name */        while(cursor != null && cursor.moveToNext()){            String id = cursor.getString(cursor.getColumnIndex(Contacts._ID));            String name = cursor.getString(cursor.getColumnIndex(Contacts.DISPLAY_NAME));            /** 再进行一次查询获取对应联系人的电话号码 */            Cursor phoneCursor = mContentResolver.query(Phone.CONTENT_URI, null, Phone.CONTACT_ID + "=" + id, null, null);            StringBuilder sb = new StringBuilder("contact_id = ").append(id).append(" " + name);            while(phoneCursor != null && phoneCursor.moveToNext()){                sb.append(" " + phoneCursor.getString(phoneCursor.getColumnIndex(Phone.NUMBER)));            }            /** 关闭Cursor对象 */            if(null != phoneCursor){                phoneCursor.close();            }            /** 显示信息 */            Log.i(TAG, sb.toString());        }        /** 关闭Cursor对象 */        if(null != cursor){            cursor.close();        }    }    /**     * 查找电话对应联系人     * @param phoneNumber 对应电话     */    private void queryContact(String phoneNumber){        Uri uri = Uri.parse(Phone.CONTENT_URI + "/filter/" + phoneNumber);        Cursor cursor = mContentResolver.query(uri, new String[]{ContactsContract.Data.DISPLAY_NAME}, null, null, null);        if(null != cursor && cursor.moveToFirst()){            showToast("电话 " + phoneNumber + " 对应联系人是 " + cursor.getString(0));        }else{            showToast("没有找到对应的联系人");        }        if(null != cursor){            cursor.close();        }    }    /**     * 增加一条数据     */    private void addContact(String name, String phone){        /** 先新建一条联系人数据并获取它对应的Id */        ContentValues values = new ContentValues();        Uri newContactUri = mContentResolver.insert(RawContacts.CONTENT_URI, values);        long contactId = ContentUris.parseId(newContactUri);        /** 添加不同信息使用的是同一个Uri,具体操作的区分是通过 MIMETYPE 来区别的 */        /** 添加刚才新建联系人的姓名 */        values.put(Data.RAW_CONTACT_ID, contactId);        values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);        values.put(StructuredName.GIVEN_NAME, name);        mContentResolver.insert(Data.CONTENT_URI, values);        values.clear();        /** 添加刚才新建联系人的电话 */        values.put(Data.RAW_CONTACT_ID, contactId);        values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);        values.put(Phone.NUMBER, phone);        values.put(Phone.TYPE, Phone.TYPE_MOBILE);        mContentResolver.insert(Data.CONTENT_URI, values);        values.clear();        /** 添加刚才新建联系人的邮箱 */        values.put(Data.RAW_CONTACT_ID, contactId);        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);        values.put(Email.DATA, "liujiescut@163.com");        values.put(Email.TYPE, Email.TYPE_WORK);        mContentResolver.insert(Data.CONTENT_URI, values);    }    /**     * 删除对应姓名的联系人     * @param name 联系人姓名     */    private void deleteContact(String name){        Cursor cursor = mContentResolver.query(RawContacts.CONTENT_URI, new String[]{ContactsContract.Data._ID}, "display_name=?", new String[]{name}, null);        if(null != cursor && cursor.moveToFirst()){            //获取联系人对应Id            int id = cursor.getInt(0);            //根据id删除data中的相应数据            mContentResolver.delete(RawContacts.CONTENT_URI, "display_name=?", new String[]{name});            mContentResolver.delete(Data.CONTENT_URI, "raw_contact_id=?", new String[]{id + ""});            showToast("delete " + name + " success");        }    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.main_btn_show_contacts:                showToast("请在控制台查看联系人输出");                new Thread(new Runnable() {                    @Override                    public void run() {                        showContacts();                    }                }).start();                break;            case R.id.main_btn_add:                String addName = mInsertNameEditText.getText().toString();                String addPhone = mInsertPhoneEditText.getText().toString();                if(!"".equals(addName) && !"".equals(addPhone)){                    addContact(addName, addPhone);                    showToast("新建联系人成功");                }else {                    showToast("联系人姓名跟手机均不能为空");                }                break;            case R.id.main_btn_delete:                String deleteName = mDeleteNameEditText.getText().toString();                if(!"".equals(deleteName)){                    deleteContact(deleteName);                }else {                    showToast("删除联系人不能为空");                }                break;            case R.id.main_btn_query:                String queryPhone = mQueryNameEditText.getText().toString();                if(!"".equals(queryPhone)){                    queryContact(queryPhone);                }else{                    showToast("查找联系人不能为空");                }                break;            default:                break;        }    }    /**     * 显示Toast信息     * @param message 要显示的信息     */    protected void showToast(String message){        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();    }}

activity_main.xml代码

<?xml version="1.0" encoding="utf-8"?><ScrollView xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        tools:context=".MainActivity"        android:orientation="vertical">        <TextView            android:layout_height="50dp"            android:layout_width="match_parent"            android:gravity="center"            android:text="按照下面提示操作系统联系人"            android:background="#ecf0f1"            android:textColor="#eb4f38"            />        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:gravity="center"            android:layout_marginTop="10dp"            android:background="#9d55b8">        <Button            android:id="@+id/main_btn_show_contacts"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentLeft="true"            android:layout_alignParentStart="true"            android:text="在Log中显示联系人" />        </LinearLayout>        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_alignParentLeft="true"            android:layout_alignParentStart="true"            android:layout_below="@+id/main_btn_show_contacts"            android:background="#00bb9c"            android:orientation="vertical"            android:layout_marginTop="10dp"            android:padding="10dp">            <EditText                android:id="@+id/main_et_add_name"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:hint="联系人姓名" />            <EditText                android:id="@+id/main_et_add_phone"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:hint="联系人电话" />            <Button                android:id="@+id/main_btn_add"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:layout_marginLeft="50dp"                android:layout_marginRight="50dp"                android:text="在联系人中插入一条数据" />        </LinearLayout>        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_alignParentLeft="true"            android:layout_alignParentStart="true"            android:layout_below="@+id/main_btn_show_contacts"            android:layout_marginTop="10dp"            android:background="#56abe4"            android:orientation="vertical"            android:padding="10dp">            <EditText                android:id="@+id/main_et_query_phone"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:hint="联系人手机号" />            <Button                android:id="@+id/main_btn_query"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:layout_marginLeft="50dp"                android:layout_marginRight="50dp"                android:text="查询输入联系人" />        </LinearLayout>        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_alignParentLeft="true"            android:layout_alignParentStart="true"            android:layout_below="@+id/main_btn_show_contacts"            android:layout_marginTop="10dp"            android:background="#11cd6e"            android:orientation="vertical"            android:padding="10dp">            <EditText                android:id="@+id/main_et_delete_name"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:hint="联系人姓名" />            <Button                android:id="@+id/main_btn_delete"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:layout_marginLeft="50dp"                android:layout_marginRight="50dp"                android:text="删除输入联系人" />        </LinearLayout>    </LinearLayout></ScrollView>


总结:由于本人用ContentProvider用的也很少,所以可能有些地方写的不是很准确,如果有错的话希望大家提出来,上面说的三个demo都可以去我的资源那里下载Android Studio源文件。






1 0
原创粉丝点击