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"); } }
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源文件。
- Android 四大组件 (三) ContentProvider 使用简介
- Android 四大组件(三)ContentProvider
- Android四大组件(三) ContentProvider
- Android四大组件之ContentProvider简介
- Android 四大组件学习之ContentProvider三
- Android四大组件之ContentProvider使用实例
- Android四大组件-ContentProvider
- Android四大组件-ContentProvider
- android四大组件---ContentProvider
- android四大组件--ContentProvider
- android四大组件--ContentProvider
- Android四大组件ContentProvider
- 【Android】四大组件(4)ContentProvider
- Android学习-四大组件(ContentProvider)
- Android四大组件之ContentProvider(上)
- Android四大组件之ContentProvider(下)
- Android四大组件(ContentProvider篇)
- android四大组件之contentprovider与service简介
- innerHTML 和 getElementsByName 在IE下面的bug 的解决
- ActionContext类与ServletActionContext类操作request域、session域内的属性
- Liunx下用代码设置ip地址
- SpringMVC+Json构建基于Restful风格的应用
- Android 可以多选的分组联系人列表
- Android 四大组件 (三) ContentProvider 使用简介
- GDI和CDC是什么
- SpringMVC学习笔记(1)之入门篇
- machine-learning第五周 上机作业
- 分布式一致性算法:Paxos (学习总结)
- 搞了一天的stm32f207芯片库函数的I2C问题终于被解决了
- Python 高级特性之生成器表达式
- 航电ACM step1.2.3 Box of bricks
- Android资料之-EditText中的inputType