首先让我整理一下凌乱的思绪!
为了学习ContentProvider,昨天我找了一个例子练习-手机通讯录的查询与添加。
结果。。。显示由于那个例子是在Android2.0一下版本的,不适合新版本。然后在去网上查询新版本的代码时,又出现了一系列的错误。。。一直搞到现在才勉强初步整理好了思路,但还是有BUG为完成!期待以后继续完善!
(最多的时间还是花在了不断的找错误和调试之中)
现在整理我还未解决问题:
1.在从“android.provider.ContactsContract.Data.CONTENT_URI ”表中删除一位联系人后,会出现一位姓名和号码都为空的联系人(没有彻底删除干净),目前好没有解决。
所遇到的问题以及解决:
1.查询联系人时报错或查询没反应。刚开始在"ContactsContract.Contacts.CONTENT_URI"表中查询时老出错误"invalid clumn data1",后来改为在“ContactsContract.Data.CONTENT_URI”中查询,结果没有丝毫反应。最后还是根据这篇文章里面的查询方法实现了查询功能:http://www.apkbus.com/android-14565-1-1.html
2.插入功能,刚开始使用老版本的方法插入联系人,结果一直报错"找不到ContactGroup之类的",后来去网上搜各种方法,最后根据这篇文章里面的方法才实现了插入功能:http://blog.csdn.net/you_and_me12/article/details/6424652
3.删除功能,我直接将老版本里面的Uri改成了现有版本里使用的类型,结果就出现了上述bug,删除联系人后,出现了一个"无姓名"的空的联系人。目前还没有解决。
*整理一些对contentResolver.query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)这个函数的理解(网上出现很多次了,不知道具体来源)
4.通讯录里面的几个表(目前理解还不够深刻)。
原文:http://www.linuxidc.com/Linux/2011-10/44927.htm
1.电话本主要信息都存在ContactsContract.Data, ContactsContract.RawContacts, ContactsContract.Contacts 三张表里
2.ContactsContract.RawContacts表里包含ContactsContract.Contacts的contact_id;
ContactsContract.Data表里有ContactsContract.RawContacts的raw_contact_id,和ContactsContract.Contacts的contact_id
Data:存储通讯录中每个人的全部信息,什么名字,电话,E-mail等一些乱七八糟和东西全在里面。
RawContacts:这个里面好像是说存储的是个人描述信息和一些唯一确定的相关的帐号
Contacts:这个好像是通讯录里面的一个人的基本描述,像什么显示的名字,分组情况,有没有电话号码之类的了。
4.查询用到的表:ContactsContract.Contacts
5.插入和删除用到的表:ContactsContract.Data
6.这篇文章里面也有说明:http://blog.csdn.net/jianxiong8814/article/details/7289153
假如一条sql语句如下:
select * from anyTable where var='const'
那么anyTable就是uri,*就是projection,selection是“var=?",selectionArgs写成这样:new String[]{'const‘},最后一个就更简单了,就是排序方式。
其实 第三个参数是sql语句where部分,如果第三个参数不带 “?”,那么第四个参数 写成 null;
*获取通讯录的具体步骤(非原创):
1)
ContentResolver contentResolver=getContentResolver();//获取 ContentResolver对象
//根据URI对象ContactsContract.Contacts.CONTENT_URI查询所有联系人;Email)等等。
2)
Cursor cursor=contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
//从Cursor对象里我们关键是要取得联系人的_id。通过它,再通过ContactsContract.CommonDataKinds的各个子类查询该_id联系人的电话
//(ContactsContract.CommonDataKinds.Phone),email(ContactsContract.CommonDataKinds.Email)等等。
比如:获取某个联系人的所有电话:
1)
int idFieldIndex=cursor.getColumnIndex(ContactsContract.Contacts._ID);
int id=cursor.getInt(idFieldIndex);//根据列名取得该联系人的id;
2)
Cursor phones=contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"=?", new String[]{Integer.toString(id)}, null);
//然后在ContactsContract.CommonDataKinds.Phone中根据相应id,查询该联系人的所有电话;
if (phones.moveToFirst()) {
int numberColumn = phones.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER);
Log.i(TAG,"得到第一个电话号码的索引为:"+numberColumn+"!");
//查询该用户所有的号码
do
{
phoneNumber += phones.getString(numberColumn) + ",";
Log.i(TAG,"号码为:"+phoneNumber);
} while(phones.moveToNext());
}
最后,这里用了do,while循环而不是while循环,因为这里第一句话是
phones.moveToFirst()
所以,要执行第一条就得用do,while.
而平时用while循环一般是不会执行这句话的,一般是默认为null,等他往下移时才是第一条语句
***最后总结一下ContentProvider
1.ContentProvider为存储和读取数据提供了统一的接口(比如查询手机通讯录就是通过Provider进行类似于数据库查询一样)
2.使用ContentProvider,应用程序可以实现数据共享(比如存入的通讯录其它程序也能用到,因为是存入了本地数据)
3.android内置的许多数据都是使用ContentProvider形式,供开发者调用的(比如通讯录)
总结:
不管什么样的理论知识还是得通过实践来证明,一个简单的小程序真的需要花费很久的时间。。。
最后说一下我受到了感触:
做一个活着的有思想的人!(参加***宣讲会有感!)
附录:
具体程序就全贴上代码了,只贴几个关键的函数,直接发工程,里面测试时用了大量的Log。(其实一个简单的程序也是能练习很多的!)
比如这个程序里面我有试着使用一个List<Activity>来关闭所有活动的Activity和给所有活动的Activity发送消息的功能,我的实现是通过所有的Activity都继承自抽象类testActivity,而testActivity继承自Activity,然后抽象类testActivity里面有一个函数showMessage(),所有子类只需要自己实现这个函数即可完成该功能。(这只是我所想到的方法)
/**功能函数,填充自己的listMap*/
private List<HashMap<String, String>> fillMaps()
{
List<HashMap<String, String>> items =
new ArrayList<HashMap<String, String>>();
Uri contactUri=ContactsContract.Contacts.CONTENT_URI;
ContentResolver contentResolver = this.getBaseContext().getContentResolver();
Cursor cursor=null;
try {
cursor = contentResolver.query(
contactUri, null, null, null, null);
if(cursor.moveToFirst())
{
int idColumn = cursor.getColumnIndex(
ContactsContract.Contacts._ID);
int displayNameColumn = cursor.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME);
//迭代查询所有用户
do
{
//得到值
String contactId = cursor.getString(idColumn);
String displayName = cursor.getString(displayNameColumn);
//先设置为空电话号码
String phoneNumber="";
//如果用户有电话号码
int numberCount = cursor.getInt(cursor.getColumnIndex(
ContactsContract.Contacts.HAS_PHONE_NUMBER));
if(numberCount>0)
{
Log.i(TAG,"查询ID为:"+contactId+"!");
Cursor phones = contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ " = " + contactId
/*+ " and " + ContactsContract.CommonDataKinds.Phone.TYPE
+ "=" + ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE*/,
null, null);
if (phones.moveToFirst()) {
int numberColumn = phones.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER);
Log.i(TAG,"得到第一个电话号码的索引为:"+numberColumn+"!");
//查询该用户所有的号码
do
{
phoneNumber += phones.getString(numberColumn) + ",";
Log.i(TAG,"号码为:"+phoneNumber);
} while(phones.moveToNext());
}
Log.i(TAG,"该联系人"+displayName+"有号码:"+numberCount+"个!");
Log.i(TAG,"号码为:"+phoneNumber);
}//查询所有的电话号码完毕
else//联系人没有号码
{
Log.i(TAG,"该联系人"+displayName+"没有号码!");
}
//添加对应信息
HashMap<String, String> i = new HashMap<String, String>();
i.put("name", displayName);
i.put("key", phoneNumber);
items.add(i);
}while(cursor.moveToNext());//查询联系人完毕
}
else//没有联系人
{
HashMap<String, String> i = new HashMap<String, String>();
i.put("name", "Your Phone");
i.put("key", "Have No Contacts.");
items.add(i);
}
Log.i(TAG,"查询成功完毕!");
} catch (Exception e) {
Log.e(TAG,"查询错误!"+e.getMessage());
}
//记得关闭
finally{
if(cursor!=null)
{
cursor.close();
}
}
return items;
}
resresh函数,功能是查询一次所有联系人并且刷新列表
private void refreshView()
{
List<HashMap<String, String>> items = fillMaps(); //查询添加到列表
//R.layout.list是一个xml文件,用来显示所有的通讯录名单和号码
ListAdapter listAdapter = new SimpleAdapter(
this,items,R.layout.list,
new String[]{"name","key"},
new int[]{R.id.list_name,R.id.list_number});
contentView.setAdapter(listAdapter);
}
添加联系人函数:
private void onInsert(Person p)
{
Log.i(TAG,"插入联系人");
try {
// 获得ContentResolver对象
ContentResolver contentResolver=this.getBaseContext().getContentResolver();
ContentValues values=new ContentValues();
// 首先想RawContacts.CONTENT_URI执行一个空值插入,目的似乎或偶去系统返回的rawContactId
Uri rawContactUri = contentResolver.insert(
RawContacts.CONTENT_URI, values);
long rawContactId = ContentUris.parseId(rawContactUri);
Uri phoneUri=null;
// 往data表入姓名数据
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
values.put(StructuredName.GIVEN_NAME, p.getName());
//插入表中
contentResolver.insert(
android.provider.ContactsContract.Data.CONTENT_URI, values);
// 往data表入电话数据
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
values.put(Phone.NUMBER, p.getNumber());
values.put(Phone.TYPE, Phone.TYPE_MOBILE);
contentResolver.insert(
android.provider.ContactsContract.Data.CONTENT_URI, values);
}
catch(Exception e)
{
Log.e(TAG,"插入出错!"+e.getMessage());
}
}
删除函数(删除的不够彻底,个人理解不太深刻)
private void onDelete(String name)
{
Log.i(TAG,"删除联系人");
/**使用一下方法删除时,信息删除了,但是联系人列表中会保留一个空值*/
// 获得ContentResolver对象
//如果使用android.provider.ContactsContract.Contacts.CONTENT_URI,则没有任何反应
ContentResolver contentResolver =this.getBaseContext().getContentResolver();
Uri url = android.provider.ContactsContract.Data.CONTENT_URI;
// 设置删除条件
String where = ContactsContract.Contacts.DISPLAY_NAME + "=?";
String[] selectionArgs = new String[]{ name };
contentResolver.delete(url, where, selectionArgs);
//Uri url2 = android.provider.ContactsContract.Contacts.CONTENT_URI;
//contentResolver.delete(url2, where, selectionArgs);
}