Android学习笔记:访问和添加通讯录中的联系人和联系人数据库表简介一

直接看代码,有详细注释。

1.联系人的数据库文件的位置

/data/data/com.android.providers.contacts/databases.contacts2.db

2.数据库中重要的几张表

contacts表:该表保存了所有的手机联系人,每个联系人占一行,该表保存了联系人的ContactID、联系次数、
         最后一次联系的时间、是否含有号码、是否被添加到收藏夹等信息。可以与表的字段名相对应
     理解。

raw_contacts表:该表保存了所有创建过的手机联系人,每个联系人占一行,表里有一列标识该联系人是否
被删除,该表保存了两个ID:RawContactID和ContactID,从而将contacts表和raw_contacts表
联系起来。该表保存了联系人的RawContactID、ContactID、联系次数、最后一次联系的时间
是否被添加到收藏夹、显示的名字、用于排序的汉语拼音等信息。

mimetypes
表:该表定义了所有的MimeTypeID,即联系人的各个字段的唯一标志。

data表:该表保存了所有创建过的手机测联系人的所有信息,每个字段占一行
,该表保存了两个ID:MimeTypeI
D和RawContactID,从而将data表和raw_contacts表联系起来。联系人的所有信息保存在列data1至data
15中,各列中保存的内容根据MimeTypeID的不同而不同。如保存号码(MimeTypeID=5)的那行数据中
,data1列保存号码,data2列保存号码类型(手机号码/家庭号码/工作号码等)。

package com.example.test;

import java.util.ArrayList;

import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.util.Log;

public class ContactsTest extends AndroidTestCase {

	private static final String tag="ContactsTest";
	public void testContacts() throws Exception //测试查询联系人
	{
		/*
	 	Content URI 是一种用于标识 Provider 数据的 URI。 Content URI 包括了整个 Provider
	 	的符号名称(authority)和表名(path)。 调用客户端的方法访问 Provider 数据表时,
	 	表的 Content URI 是参数之一。Uri uri=Uri.parse("content://com.android.contacts/contacts");
	 */
		//这里的字符串com.android.contacts 是 Provider 的 authority 部分, 字符串 contacts 是数据表的 path 部分。 字符串 content:// (scheme)是必须指定的,以表明这是一个 Content URI。
		Uri uri=Uri.parse("content://com.android.contacts/contacts");
		ContentResolver resolver=this.getContext().getContentResolver();
		Cursor cursor=resolver.query(uri, new String[]{"_id"}, null, null, null);
		while(cursor.moveToNext())
		{
			int contactid=cursor.getInt(0);
			StringBuffer sb=new StringBuffer("contactid=");
			sb.append(contactid);
			uri=Uri.parse("content://com.android.contacts/contacts/"+contactid+"/data");
			/*
			Cursor = getContentResolver().query(
			    uri,   							// 联系人的URI
			    mProjection,                    // 需要返回的列
			    mSelectionClause,               // 查询条件
			    mSelectionArgs,                 // 查询条件的参数
			    mSortOrder);                    // 返回结果的排序要求
			    */
			Cursor datacursor=resolver.query(uri	//联系人的URI
					, new String[]{"mimetype","data1","data2"}//需要返回的列
					, null				//查询条件
					, null				//查询条件的参数
					, null);			//返回结果的排序要求
			while(datacursor.moveToNext())
			{
				String data=datacursor.getString(datacursor.getColumnIndex("data1"));
				String type=datacursor.getString(datacursor.getColumnIndex("mimetype"));
				if("vnd.android.cursor.item/name".equals(type))
				{
					sb.append(",name="+data);
				}
				else if("vnd.android.cursor.item/email_v2".equals(type))
				{
					sb.append(",email="+data);
				}else if("vnd.android.cursor.item/phone_v2".equals(type)){
					sb.append(",phone="+data);
				}
			}
			Log.i(tag, sb.toString());
		}
		cursor.close();
	}
	public void testContactsNameByNumer() throws Exception
	{
		String number="15241499053";
		//Provider 提供了对单条记录的访问能力,只要在 URI 后面跟一个 ID 值即可。 例如,要根据电话找到联系人,只需要在后面加上number,可以使用以下 Content URI:
		Uri uri=Uri.parse("content://com.android.contacts/data/phones/filter/"+number);
		ContentResolver resolver=this.getContext().getContentResolver();
		Cursor cursor=resolver.query(uri, new String[]{"display_name"}, null, null, null);
		while(cursor.moveToNext())
		{
			String name=cursor.getString(0);
			Log.i(tag,name);
		}
		cursor.close();
	}
	/*
	 调用 ContentResolver.insert() 方法可以将数据插入 Provider 到中去。 该方法将在 Provider 中插入新数据行,并返回一个指向改行数据的 Content URI。 以下代码将在 com.android.contacts Provider 中插入一条新的联系人:

新行的数据存放在一个 ContentValues 对象中, 对象中,这个对象类似于只包含一条数据的游标。 该对象中的各个字段的类型可以各不相同。如果不需要指定值,可以用 ContentValues.putNull() 方法置为 null。

上述代码并没有给 _ID 字段赋值,因为这个字段是由系统自动维护的。 Provider 会自动给插入行的 _ID 字段赋一个唯一值,并且通常把它作为表的主键使用。 

	 */
	public void testAddContacts() throws Exception
	{
		Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
		ContentResolver resolver=getContext().getContentResolver();
		ContentValues values=new ContentValues();

		long contactid=ContentUris.parseId(resolver.insert(uri, values));
		uri=Uri.parse("content://com.android.contacts/data");
		//添加姓名
		values.put("raw_contact_id", contactid);
		values.put("mimetype", "vnd.android.cursor.item/name");
		values.put("data2", "王超");
		resolver.insert(uri, values);
		//添加电话
		values.put("raw_contact_id", contactid);
		values.put("mimetype", "vnd.android.cursor.item/phone_v2");
		values.put("data2", "2");
		values.put("data1", "4399101");
		resolver.insert(uri, values);
		//Email
		values.put("raw_contact_id", contactid);
		values.put("mimetype", "vnd.android.cursor.item/email_v2");
		values.put("data2", "2");
		values.put("data1", "[email protected]");
		resolver.insert(uri, values);
	}
	/*
	 在开发应用时,访问 Provider 还有其他三种重要的形式:

		批量访问:通过 ContentProviderOperation 类的一些方法,可以创建批量访问任务,并通过 ContentResolver.applyBatch() 来提交。
		异步查询:在单独的线程中执行查询。有一种方案是用 CursorLoader 对象来实现。在指南 Loaders 中给出了示例。
		利用 Intent 访问数据: 虽然不能向 Provider 直接发送 Intent,但可以向 Provider 所在应用发送 Intent, 通常这些应用都具备修改 Provider 数据的能力。
		下面这种就是以通过 ContentProviderOperation进行的批量添加。
	 */
	public void testAddContact2() throws Exception{
		Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
		ContentResolver resolver=getContext().getContentResolver();
		//创建一个 ContentProviderOperation 对象的数组,并通过 ContentResolver.applyBatch() 方法将它传给 Content Provider。
		ArrayList<ContentProviderOperation> operations=new ArrayList<ContentProviderOperation>();
		ContentProviderOperation op1=ContentProviderOperation.newInsert(uri)
				.withValue("account_name", null)
				.build();
		operations.add(op1);
		/*
		 * 在调用时不是指定某个 Content URI,而是要给出 Content Provider 的 authority。
		 * 数组中的每个 ContentProviderOperation 对象可以对不同的数据表进行操作。
		 *  ContentResolver.applyBatch() 返回的结果也是数组。
		 */
		uri=Uri.parse("ontent://com.android.contacts/data");
		ContentProviderOperation op2=ContentProviderOperation.newInsert(uri)
				.withValueBackReference("raw_contact_id", 0)
				.withValue("mimetype", "vnd.android.cursor.item/name")
				.withValue("data2", "李小龙")
				.build();
		operations.add(op2);

		ContentProviderOperation op3=ContentProviderOperation.newInsert(uri)
				.withValueBackReference("raw_contact_id", 0)
				.withValue("mimetype", "vnd.android.cursor.item/phone_v2")
				.withValue("data1", "110119")
				.withValue("data2", "2")
				.build();
		operations.add(op3);

		ContentProviderOperation op4=ContentProviderOperation.newInsert(uri)
				.withValueBackReference("raw_contact_id", 0)
				.withValue("mimetype", "vnd.android.cursor.item/email_v2")
				.withValue("data1", "[email protected]")
				.withValue("data2", "2")
				.build();
		operations.add(op4);

		resolver.applyBatch("com.android.contacts", operations);
	}
}

完成以上测试代码还需要添加对联系人表操作的响应权限。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.contacts"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <uses-library android:name="android.test.runner"/>
    </application>
    <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.contacts"></instrumentation>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>"
</manifest>

这是对联系人操作对应的权限:

<uses-permission android:name="android.permission.READ_CONTACTS"

/>

<uses-permission android:name="android.permission.WRITE_CONTACTS"

/>

这是对测试单元对应的权限和依赖库:

<instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.contacts"></instrumentation>
 <uses-library android:name="android.test.runner"/>
时间: 2024-08-07 22:54:14

Android学习笔记:访问和添加通讯录中的联系人和联系人数据库表简介一的相关文章

Android学习笔记四:添加Source

问题描述 Source not foundThe JAR file D:\.....\sdk\platforms\android-20\android.jar has no source attachment. 问题原因及解决办法 1. 使用SDK Manager下载最新版本的Sources for Android SDK 一般文件下载目录默认在SDK下的sources文件中即 \adt-bundle-windows-x86_64-20130522\sdk\sources\android-20

sqlite学习笔记7:C/C++中使用sqlite之打开数据库

数据库的基本内容前面都已经说得差不多了,接下看看怎样在C语言中使用sqlite. 一 接口 sqlite3_open(const char *filename, sqlite3 **ppDb) 打开数据库,如果数据库不存在则新建一个数据库,并打开 sqlite3_close(sqlite3*) 关闭数据库,如果关闭之前还存在没有执行完的语句,将会返回SQLITE_BUSY 二 实例 1 目录结构 Projects{ main.c// 代码所在文件 sqlite{// 官网下载下来的sqlite压

Android学习笔记二十一.使用ContentProvider实现数据共享(四).操作系统(联系人)的ContentProvider

Android系统本身提供了大量的ContentProvider,例如联系人信息.系统的多媒体信息等,我们开发的应用程序主要是通过ContentResolver来调用系统的ContentProvider提供的query().insert().update()和delete()方法来获取Android内部的数据. 一.如何使用ContentResolver操作系统ContentProvider暴露的内部数据? 1.调用Activity的getContentResolver()获取ContentRe

sqlite学习笔记7:C语言中使用sqlite之打开数据库

数据库的基本内容前面都已经说得差点儿相同了.接下看看如何在C语言中使用sqlite. 一 接口 sqlite3_open(const char *filename, sqlite3 **ppDb) 打开数据库,假设数据库不存在则新建一个数据库,并打开 sqlite3_close(sqlite3*) 关闭数据库.假设关闭之前还存在没有运行完的语句,将会返回SQLITE_BUSY 二 实例 1 文件夹结构 Projects{ main.c// 代码所在文件 sqlite{// 官网下载下来的sqli

Android学习笔记:如何设置ImageView中图片的显示方式

我们在用ImageView显示图片时,很多情况下图片的大小与ImageView的尺寸不是完全一样的.这时就涉及到该如何设置显示图片了. ImageView有个重要的属性是ScaleType,该属性用以表示显示图片的方式,共有很多种取值.另外也可以在xml文件中设置ImageView的android:scaleType属性达到调整效果. 这里我们介绍各种设置的含义: 1.ScaleType.CENTER(对应xml文件中为android:scaleType="center") 图片将位于

Android学习笔记(四九):通过Content Provider访问数据

在上次笔记中,我们编写了自己的Provider,这次笔记,我们将通过Content Provider的Uri接口对数据进行访问,重写Android学习笔记(四二)中例子.在这里我们不在充分描述相关UI如何编写,可以到笔记(四二)中详细查看,重点讲述如何实现数据的访问. 读取信息 读取信息方式,在笔记(四七)中已经介绍,代码如下 private voidread(){     /* 通过managedQuery读取,第1参数表示URI, 第2参数表示所需读取的信息,第3个参数是限制条件,类似SQL

Android学习笔记_78_ Android开发中使用软引用和弱引用防止内存溢出

在<Effective Java 2nd Edition>中,第6条"消除过期的对象引用"提到,虽然Java有 垃圾回收机制,但是只要是自己管理的内存,就应该警惕内存泄露的问题,例如的对象池.缓存中的过期对象都有可能引发内存泄露的问题.书中还提到可以用 WeakHashMap来作为缓存的容器可以有效解决这一问题.之前也确实遇到过类似问题,但是没有接触过"弱引用"相关的问题,于是查阅了一些资料. <Java 理论与实践: 用弱引用堵住内存泄漏>

Android学习笔记(十四)——在运行时添加碎片(附源码)

在运行时添加碎片 点击获取源码 将UI分割为多个可配置的部分是碎片的优势之一,但其真正强大之处在于可在运行时动态地把它们添加到活动中. 1.使用上一篇创建的Fragments项目,在main.xml文件中注释掉两个<fragment>元素: 2.在FragmentActivity.java中添加下面的代码: FragmentManager fragmentManager = getSupportFragmentManager();//向活动添加碎片 FragmentTransaction fr

Android学习笔记(四三):文件访问

之前我们学习了通过preference和SQLite数据库进行数据存储,也可以通过文件方式.文件可以是在应用打包时预置,也可以是应用所生成. 文件访问有两种方式:一:静态数据的文件可以防止在res/raw中,这些文件是只读的,只有在应用版本升级的时候进行修改,或者我们先读出这些数据,通过 reference的方式来处理,这样以后可以进行修订,但是这种方式,会有两份数据保存.二:另一种方式是通过URL访问文件,动态数据的读取也可以采用SQLite3的方式. res/raw/下静态文件的读取 在re