Android ContentProvider 获取和插入联系人
来源:互联网 发布:烟花算法 编辑:程序博客网 时间:2024/04/30 02:24
项目简介:
该项目为获取手机联系人,插入手机联系人。
详细介绍:
该应用共三个按钮,一个ListView
当用户点击“获取所有联系人”按钮时,该应用将会查找到所有的联系人,显示在ListView上
当用户点击“添加联系人(不安全)”按钮时,该应用将会自动添加一个联系人到手机中,但是如果遇到突发情况,程序可能执行到一半,联系人信息可能插入不全。如在插入联系人姓名、电话、email时候,当插入姓名后断电,将会导致插入的联系人只有姓名,没有电话、email。
当用户点击“添加联系人(安全)”按钮时,该应用自动添加一个联系人到手机中。该方法是安全的,即使遇到突发情况,要么联系人信息全部插入到数据库中,要么就没有插入任何信息。不存在只插入一般信息的情况。
该应用涉及到的知识有:
1.联系人三张主要的表:
raw_contacts表: 主要存放联系人的id
contact_id:联系人的id
data表:存放联系人的详细信息。该表的每一行都存储联系人的一个信息
data1:联系人具体的信息
raw_contact_id:该行信息所属联系人得id
mimetype_id:该行属于什么信息
mimetypes表:2.如何获取手机联系人
首先在raw_dontacts表中获取联系人的id,即contact_id字段的值
然后根据联系人的id在data表中查询联系人的信息,即查询条件是raw_contact_id=?
注意的是:
在这里,Android系统查询data表的时候,该表中的 mimetype_id 是无法查询到了的,而是官方直接在该内容提供者的查询方法中使用了关联查询,把data表中的mimetype_id先查询到,然后再到mimetypes表中查询到该数字对应的mimetype字段的值,然后封装在一个Cursor对象中。所以,直接在data表中查询mimetype字段即可。
3.如何插入联系人
实际上就是查询联系人的逆向工程。
即首先在raw_dontacts表中插入一个联系人,获取该联系人的id
然年再在data表中插入具体的信息4.删除联系人
删除联系人是十分简单的。只要把raw_dontacts表中的联系人的id(即contact_id字段)变为null即可,这样系统就无法查询到联系人了。但是联系人的信息仍然保存在data表中。这其实就是Android系统的机制。
所以,从旧手机中获取联系人信息就是这个原理,因为data表信息是一直存在的- 5.如何获取联系人的ContentProvider的Uri
在Android源码下按照该路径: packages\providers\ContactsProvider,然后打开清单文件,就可以找到ContactsProvider2(这里有个2,说明之间有个1,但是2更好用,所以1就退出了历史舞台),获取该内容提供者的一些信息。再根据:src\com\android\providers\contacts寻找到ContactsProvider2.java 文件,打开后搜索“addUri”,即可寻找到UriMatcher的匹配项,即可知道该内容提供者的Uri
注意:
- 1.查询联系人,写入联系人都是需要权限的
- 2.最好现在当前项目先用Android的单元测试先对自己的代码测试一下,然后再到Activity中去执行,避免重复部署浪费时间
步骤:
1.创建一个Android应用。
接下来要用从手机中读取联系人,为了方便,创建一个javaBean,即person类:
public class Person { private String name; private String phone; private String email; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "Contact [_id=" + name + ", phone=" + phone + ", email=" + email + "]"; }}
2.布局文件
编写activity_main.xml文件
<LinearLayout 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" android:orientation="vertical" tools:context="hhh.exercise.hcontentprovider_d.MainActivity" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/black" android:onClick="click1" android:text="获取所有联系人" android:textColor="#00ff00" android:textSize="30sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/black" android:onClick="click2" android:text="添加联系人(不安全)" android:textColor="#00ff00" android:textSize="30sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/black" android:onClick="click3" android:text="添加联系人(安全)" android:textColor="#00ff00" android:textSize="30sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/tv_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Name" android:textColor="#ff0000" /> <TextView android:id="@+id/tv_phone" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Phone" android:textColor="#00ff00" /> <TextView android:id="@+id/tv_email" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Email" android:textColor="#000000" /> </LinearLayout> <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView></LinearLayout>
这个布局就是三个按钮,分别用来获取联系人,以及两种添加联系人的方式。按钮下面是三个TestView,显示一些必要的信息,在下面就是一个ListView,用于将查找到的联系人显示在上面,布局界面如下:
既然布局中有ListView,那么就要写另一个布局文件,用来填充ListView:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:id="@+id/tv_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Name" android:textColor="#ff0000" /> <TextView android:id="@+id/tv_phone" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Phone" android:textColor="#00ff00" /> <TextView android:id="@+id/tv_email" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Email" android:textColor="#000000" /></LinearLayout>
界面如下所示:
其实就是三个TestView,用来显示联系人的信息
3.Activity
MainActivity 的代码如下:
import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import android.app.Activity;import android.content.ContentProviderOperation;import android.content.ContentResolver;import android.content.ContentValues;import android.content.OperationApplicationException;import android.content.ContentProviderOperation.Builder;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.os.RemoteException;import android.view.View;import android.widget.ListView;import android.widget.SimpleAdapter;import hhh.exercise.domain.Person;public class MainActivity extends Activity { private ListView lv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv = (ListView) findViewById(R.id.lv); } /** * 查询手机中所有的联系人,并显示在列表上。 * * 查询分为两步:1、往raw_contacts表中查询到联系人的id。 2、根据查询到的联系人id到data表中查找数据 */ public void click1(View view) { // 创建一个List,存储所有的联系人 List<Person> list = new ArrayList<Person>(); ContentResolver resolver = getContentResolver(); // 从raw_contacts表中查询到联系人的id Cursor cursorContactId = resolver.query(Uri.parse("content://com.android.contacts/raw_contacts"), new String[] { "_id" }, null, null, null); while (cursorContactId.moveToNext()) { // 获取联系人的id String _id = cursorContactId.getString(cursorContactId.getColumnIndex("_id")); // 根据联系人的id在data表中查询联系人的数据 // mimetype: 内容类型。用来判断数据是什么类型的 // data1、data2:是我们想要查询的数据.其中data2是对data1的补充说明(例如:data1表示电话,data2表示的是电话的类型,可能是家庭电话、公司电话等) /* * 在这里,Android系统查询data表的时候,该表中的 mimetype_id * 是无法查询到了的,而是直接在该内容提供者的查询方法中使用了关联查询,把data表中的mimetype_id先查询到, 然后再到 * mimetypes表中查询到该数字对应的mimetype字段的值,然后封装在一个Cursor对象中。所以, * 直接在data表中查询mimetype字段即可。 * 可以直接先查询出该表所有的字段,返回一个cursor,然后使用cursor.getColumnNames()获取到该表的所有的字段 * ,即可以知道data表的查询字段可以传入那些参宿 */ Cursor cursorData = resolver.query(Uri.parse("content://com.android.contacts/data"), new String[] { "mimetype", "data1" }, "raw_contact_id=?", new String[] { _id }, null); Person person = new Person(); while (cursorData.moveToNext()) { // 获得数据的类型(数据data1是姓名、电话还是其他) String mimetype = cursorData.getString(cursorData.getColumnIndex("mimetype")); String data1 = cursorData.getString(cursorData.getColumnIndex("data1")); if (mimetype.equals("vnd.android.cursor.item/phone_v2")) { // vnd.android.cursor.item/phone_v2表示该数据是电话 person.setPhone(data1); } else if (mimetype.equals("vnd.android.cursor.item/email_v2")) { // vnd.android.cursor.item/email_v2表示该数据是邮件 person.setEmail(data1); } else if (mimetype.equals("vnd.android.cursor.item/name")) { // vnd.android.cursor.item/name表示该数据是姓名 person.setName(data1); } } // 把联系人添加到list中 list.add(person); } // 列表显示联系人 show(list); } /** * 添加联系人 添加联系人方法一:不安全版 需要获取通讯录的写权限 * 这个方法有些错误:添加联系人分为多个操作,可能存在中断的情况,导致数据只添加了部分。所以需要同步。 * * 添加联系人分为两步: 1、往raw_contacts表中添加联系人的id。 2、把联系人的各项数据添加到data表中 * * @throws Exception */ public void click2(View view) { ContentResolver resolver = getContentResolver(); // 1先在raw_contacts表中插入联系人的id。要获取到联系人的id,只要获取到该表中的主键的id,然后加上1就是插入的联系人的id Cursor cursorContactId = resolver.query(Uri.parse("content://com.android.contacts/raw_contacts"), null, null, null, null); // 默认情况下,数据库没有数据,联系人的id就是1 int contact_id = 1; if (cursorContactId.moveToLast()) { // 移动到Cursor对象的末尾,拿到主键,并加一 int _id = cursorContactId.getInt(cursorContactId.getColumnIndex("_id")); contact_id = _id + 1; } ContentValues values = new ContentValues(); values.put("contact_id", contact_id); resolver.insert(Uri.parse("content://com.android.contacts/raw_contacts"), values); // 2.把数据插入到data表中 // 添加姓名。 values.clear(); values.put("raw_contact_id", contact_id); values.put("mimetype", "vnd.android.cursor.item/name"); values.put("data1", "lisi"); resolver.insert(Uri.parse("content://com.android.contacts/data"), values); // 添加电话 values.clear(); values.put("raw_contact_id", contact_id); values.put("mimetype", "vnd.android.cursor.item/phone_v2"); values.put("data1", "004"); // 指定电话的类型 values.put("data2", "2"); resolver.insert(Uri.parse("content://com.android.contacts/data"), values); // 添加email values.clear(); values.put("raw_contact_id", contact_id); values.put("mimetype", "vnd.android.cursor.item/email_v2"); values.put("data1", "004@qq.com"); values.put("data2", "2"); resolver.insert(Uri.parse("content://com.android.contacts/data"), values); } /** * 添加联系人方法二:安全版 在同一个事务中完成联系人各项数据的添加。 * 系统是通过内容提供者添加联系人。我们可以先把这些操作传给一个集合,再把这个集合传给内容提供者。由内容提供者内部开好事务后,在迭代这些集合中的操作,使得这些操作都在同一个事务中执行。 * * @throws OperationApplicationException * @throws RemoteException * */ public void click3(View view) throws RemoteException, OperationApplicationException { Uri uri = Uri.parse("content://com.android.contacts/raw_contacts"); ContentResolver resolver = getContentResolver(); // 用ArrayList封装所有的操作 ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(); // 往集合里面传入操作(此时操作并没有执行,仅仅是作为一个对象传入) // 为添加联系人操作新建对象。使用ContentProviderOperation的静态方法newInsert Builder builder = ContentProviderOperation.newInsert(uri); // withValue为字段赋值。可以随便找一个列设为空值或者需要设置的值。为下文获取做铺垫(account_name是谷歌的账号) builder.withValue("account_name", null); // 在使用build方法构建ContentProviderOperation的操作对象.得到了这个操作对象,但是并没有执行(也就是说没有完成插入操作)。这段代码仅仅是得到了操作对象而已 ContentProviderOperation op1 = builder.build(); // 添加操作对象。这个操作对象是第一个,在Arraylist集合中的位置是0号位置。 operations.add(op1); // 往集合中添加姓名 Uri uri2 = Uri.parse("content://com.android.contacts/data"); // 无法知道上一个添加入raw_contacts表的id,所以要采用withValueBackReference获取raw_contact_id,其中0代表第一个操作对象在集合中的位置。 // 这个withValueBackReference方法的作用是:使用索引所对应的集合中的对象执行后所返回的记录的id作为第一个参数字段的值。在本题中,就是使用op1执行后所返回的id作为raw_contact_id的值。 ContentProviderOperation op2 = ContentProviderOperation.newInsert(uri2) .withValueBackReference("raw_contact_id", 0) .withValue("mimetype", "vnd.android.cursor.item/name") .withValue("data2", "wangwu").build(); operations.add(op2); // 添加电话 ContentProviderOperation op3 = ContentProviderOperation.newInsert(uri2) .withValueBackReference("raw_contact_id", 0) .withValue("mimetype", "vnd.android.cursor.item/phone_v2") .withValue("data1", "005") .withValue("data2", "2").build(); operations.add(op3); // email ContentProviderOperation op4 = ContentProviderOperation.newInsert(uri2) .withValueBackReference("raw_contact_id", 0) .withValue("mimetype", "vnd.android.cursor.item/email_v2") .withValue("data1", "005@QQ.COM") .withValue("data2", "2").build(); operations.add(op4); // 使用安卓内部的API应用批量操作(即applyBatch)。第一个参数是内容提供者的主机名,第二个参数是要批量执行的操作 resolver.applyBatch("com.android.contacts", operations); } /** * 列表显示联系人 */ private void show(List<Person> list) { List<Map<String, String>> data = new ArrayList<Map<String, String>>(); for (Person person : list) { Map<String, String> map = new HashMap<String, String>(); map.put("name", person.getName()); map.put("phone", person.getPhone()); map.put("email", person.getEmail()); data.add(map); } SimpleAdapter adapter = new SimpleAdapter(getApplicationContext(), data, R.layout.item, new String[] { "name", "phone", "email" }, new int[] { R.id.tv_name, R.id.tv_phone, R.id.tv_email }); lv.setAdapter(adapter); }}
4.清单文件
读取手机联系人和添加手机联系人都要权限的
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" />
5.完成,测试效果
进入界面后,点击获取所有联系人
点击添加联系人(不安全)和添加联系人(安全)两个按钮,没有任何反应,在点击获取所有联系人,如下所示:
可以看到两个新增的联系人的确添加进去了
- Android ContentProvider 获取和插入联系人
- Android-ContentProvider读取和插入手机联系人
- android中ContentProvider实现联系人的读取和插入
- android-ContentProvider获取联系人信息
- Android-contentprovider 获取手机联系人
- Android插入和获取联系人详情
- Android 开发 ContentProvider 获取歌曲列表和联系人的例子
- Android 开发 ContentProvider 获取歌曲列表和联系人的例子
- 64.内容提供者ContentProvider--获取系统的联系人,插入联系人
- Android -ContentProvider之获取手机联系人
- Android ContentProvider+获取系统联系人小Demo
- Android 利用ContentProvider获取联系人信息
- Android:ContentProvider获取手机联系人列表
- Android ContentProvider(获取手机联系人)
- android获取联系人信息,插入联系人
- 安卓中使用ContentProvider获取和添加联系人
- ContentProvider获取联系人信息
- ContentProvider如何获取联系人
- windows消息机制
- 计算CDS中密码子的数量
- Android ContentProvider 查询备份插入短信
- Linux文件特殊权限:SUID,SGID,SBIT(黏滞位)的简单介绍
- Discuz!出现错误Too many connections解决方法
- Android ContentProvider 获取和插入联系人
- Leap Motion
- Python:渗透测试开源项目【源码值得精读】
- Java基础回顾--jav集合2 Map,List与Set的区别
- input赋值时的空格问题
- ansible常用命令
- 签名文件的生成及查看签名信息
- Android Fragment 碎片的初步使用
- C语言复习笔记 5