Android通讯录管理(获取联系人、通话记录、短信消息)

前言:前阵子主要是记录了如何对联系人的一些操作,比如搜索,全选、反选和删除等在实际开发中可能需要实现的功能,本篇博客是小巫从一个别人开源的一个项目抽取出来的部分内容,把它给简化出来,可以让需要的朋友清楚知道如何对Android数据库操作,异步查询数据库获取我们需要的内容。由于内容比较多,我将分三篇博客来讲述获取联系人、通话记录、短信消息的实现。
 
也许你根本就没耐心看,源码在这里http://download.csdn.net/detail/wwj_748/6962865,骚年去下吧。
 
上面的是获取联系人的界面效果,实现分组显示联系人,快速索引条查找联系人,下面是实现:
从权限开始: 
  1. <!-- 读联系*限 -->
  2. <uses-permission android:name="android.permission.READ_CONTACTS" />
  3. <!-- 写联系*限 -->
  4. <uses-permission android:name="android.permission.WRITE_CONTACTS" />
  5. <!-- 拨号权限 -->
  6. <uses-permission android:name="android.permission.CALL_PHONE" />
  7. <!-- 读短信权限 -->
  8. <uses-permission android:name="android.permission.READ_SMS" />
界面布局:
/Contact_Demo/res/layout/contact_list_view.xml 
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:id="@+id/contact_list_view"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:background="#000000" >
  7. <com.suntek.contact.view.SlidingLinearLayout
  8. android:id="@+id/slidingview"
  9. android:layout_width="match_parent"
  10. android:layout_height="match_parent"
  11. android:layout_alignParentTop="true" >
  12. <ListView
  13. android:id="@+id/contact_list"
  14. android:layout_width="match_parent"
  15. android:layout_height="match_parent"
  16. android:cacheColorHint="#000000"
  17. android:divider="#00000000"
  18. android:fadingEdge="none"
  19. android:scrollbars="none"
  20. android:scrollingCache="false"
  21. android:visibility="visible" />
  22. </com.suntek.contact.view.SlidingLinearLayout>
  23. <com.suntek.contact.view.QuickAlphabeticBar
  24. android:id="@+id/fast_scroller"
  25. android:layout_width="22dp"
  26. android:layout_height="match_parent"
  27. android:layout_alignParentRight="true"
  28. android:layout_gravity="top|right|center"
  29. android:layout_marginTop="0dip"
  30. android:background="@null"
  31. android:scaleType="centerInside"
  32. android:src="@drawable/dic_background" >
  33. </com.suntek.contact.view.QuickAlphabeticBar>
  34. <TextView
  35. android:id="@+id/fast_position"
  36. android:layout_width="70dip"
  37. android:layout_height="70dip"
  38. android:layout_centerInParent="true"
  39. android:layout_gravity="center_horizontal|top"
  40. android:layout_margin="34dip"
  41. android:background="@drawable/sort_icon_bg_click"
  42. android:gravity="center"
  43. android:padding="2dip"
  44. android:textColor="#404040"
  45. android:textSize="48dip"
  46. android:visibility="invisible" />
  47. </RelativeLayout>

/Contact_Demo/res/layout/contact_list_item.xml 

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="wrap_content" >
  5. <!-- 首字母 -->
  6. <TextView
  7. android:id="@+id/alpha"
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"
  10. android:background="#333333"
  11. android:paddingLeft="10dip"
  12. android:textColor="#FFFFFF"
  13. android:visibility="gone" />
  14. <!-- 联系人信息 -->
  15. <QuickContactBadge
  16. android:id="@+id/qcb"
  17. android:layout_width="75dip"
  18. android:layout_height="75dip"
  19. android:layout_alignParentLeft="true"
  20. android:layout_below="@+id/alpha"
  21. android:layout_marginBottom="3dip"
  22. android:layout_marginTop="3dip"
  23. android:src="@drawable/touxiang" />
  24. <TextView
  25. android:id="@+id/name"
  26. android:layout_width="wrap_content"
  27. android:layout_height="wrap_content"
  28. android:layout_centerVertical="true"
  29. android:layout_marginLeft="5.0dip"
  30. android:layout_toRightOf="@+id/qcb"
  31. android:singleLine="true"
  32. android:textAppearance="?android:textAppearanceLarge"
  33. android:textColor="#FFFFFF" />
  34. <TextView
  35. android:id="@+id/number"
  36. android:layout_width="wrap_content"
  37. android:layout_height="wrap_content"
  38. android:layout_alignParentBottom="true"
  39. android:layout_marginLeft="5.0dip"
  40. android:layout_toRightOf="@+id/qcb"
  41. android:singleLine="true"
  42. android:textAppearance="?android:textAppearanceSmall"
  43. android:textColor="#FFFFFF" />
  44. </RelativeLayout>
代码实现:
1. 先定义一个实体类,用来保存联系人信息
/Contact_Demo/src/com/suntek/contact/model/ContactBean.java 
  1. package com.suntek.contact.model;
  2. public class ContactBean {
  3. private int contactId; //id
  4. private String desplayName;//姓名
  5. private String phoneNum; // 电话号码
  6. private String sortKey; // 排序用的
  7. private Long photoId; // 图片id
  8. private String lookUpKey;
  9. private int selected = 0;
  10. private String formattedNumber;
  11. private String pinyin; // 姓名拼音
  12. public int getContactId() {
  13. return contactId;
  14. }
  15. public void setContactId(int contactId) {
  16. this.contactId = contactId;
  17. }
  18. public String getDesplayName() {
  19. return desplayName;
  20. }
  21. public void setDesplayName(String desplayName) {
  22. this.desplayName = desplayName;
  23. }
  24. public String getPhoneNum() {
  25. return phoneNum;
  26. }
  27. public void setPhoneNum(String phoneNum) {
  28. this.phoneNum = phoneNum;
  29. }
  30. public String getSortKey() {
  31. return sortKey;
  32. }
  33. public void setSortKey(String sortKey) {
  34. this.sortKey = sortKey;
  35. }
  36. public Long getPhotoId() {
  37. return photoId;
  38. }
  39. public void setPhotoId(Long photoId) {
  40. this.photoId = photoId;
  41. }
  42. public String getLookUpKey() {
  43. return lookUpKey;
  44. }
  45. public void setLookUpKey(String lookUpKey) {
  46. this.lookUpKey = lookUpKey;
  47. }
  48. public int getSelected() {
  49. return selected;
  50. }
  51. public void setSelected(int selected) {
  52. this.selected = selected;
  53. }
  54. public String getFormattedNumber() {
  55. return formattedNumber;
  56. }
  57. public void setFormattedNumber(String formattedNumber) {
  58. this.formattedNumber = formattedNumber;
  59. }
  60. public String getPinyin() {
  61. return pinyin;
  62. }
  63. public void setPinyin(String pinyin) {
  64. this.pinyin = pinyin;
  65. }
  66. }
适配器:
/Contact_Demo/src/com/suntek/contact/adapter/ContactListAdapter.java 
  1. package com.suntek.contact.adapter;
  2. import java.io.InputStream;
  3. import java.util.ArrayList;
  4. import java.util.Collections;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.Set;
  8. import java.util.regex.Pattern;
  9. import android.content.ContentUris;
  10. import android.content.Context;
  11. import android.graphics.Bitmap;
  12. import android.graphics.BitmapFactory;
  13. import android.net.Uri;
  14. import android.provider.ContactsContract;
  15. import android.provider.ContactsContract.Contacts;
  16. import android.view.LayoutInflater;
  17. import android.view.View;
  18. import android.view.ViewGroup;
  19. import android.widget.BaseAdapter;
  20. import android.widget.QuickContactBadge;
  21. import android.widget.TextView;
  22. import com.suntek.contact.R;
  23. import com.suntek.contact.model.ContactBean;
  24. import com.suntek.contact.view.QuickAlphabeticBar;
  25. public class ContactListAdapter extends BaseAdapter {
  26. private LayoutInflater inflater;
  27. private List<ContactBean> list;
  28. private HashMap<String, Integer> alphaIndexer; // 字母索引
  29. private String[] sections; // 存储每个章节
  30. private Context ctx; // 上下文
  31. public ContactListAdapter(Context context, List<ContactBean> list,
  32. QuickAlphabeticBar alpha) {
  33. this.ctx = context;
  34. this.inflater = LayoutInflater.from(context);
  35. this.list = list;
  36. this.alphaIndexer = new HashMap<String, Integer>();
  37. this.sections = new String[list.size()];
  38. for (int i = 0; i < list.size(); i++) {
  39. // 得到字母
  40. String name = getAlpha(list.get(i).getSortKey());
  41. if (!alphaIndexer.containsKey(name)) {
  42. alphaIndexer.put(name, i);
  43. }
  44. }
  45. Set<String> sectionLetters = alphaIndexer.keySet();
  46. ArrayList<String> sectionList = new ArrayList<String>(sectionLetters);
  47. Collections.sort(sectionList); // 根据首字母进行排序
  48. sections = new String[sectionList.size()];
  49. sectionList.toArray(sections);
  50. alpha.setAlphaIndexer(alphaIndexer);
  51. }
  52. @Override
  53. public int getCount() {
  54. return list.size();
  55. }
  56. @Override
  57. public Object getItem(int position) {
  58. return list.get(position);
  59. }
  60. @Override
  61. public long getItemId(int position) {
  62. return position;
  63. }
  64. public void remove(int position) {
  65. list.remove(position);
  66. }
  67. @Override
  68. public View getView(int position, View convertView, ViewGroup parent) {
  69. ViewHolder holder;
  70. if (convertView == null) {
  71. convertView = inflater.inflate(R.layout.contact_list_item, null);
  72. holder = new ViewHolder();
  73. holder.quickContactBadge = (QuickContactBadge) convertView
  74. .findViewById(R.id.qcb);
  75. holder.alpha = (TextView) convertView.findViewById(R.id.alpha);
  76. holder.name = (TextView) convertView.findViewById(R.id.name);
  77. holder.number = (TextView) convertView.findViewById(R.id.number);
  78. convertView.setTag(holder);
  79. } else {
  80. holder = (ViewHolder) convertView.getTag();
  81. }
  82. ContactBean contact = list.get(position);
  83. String name = contact.getDesplayName();
  84. String number = contact.getPhoneNum();
  85. holder.name.setText(name);
  86. holder.number.setText(number);
  87. holder.quickContactBadge.assignContactUri(Contacts.getLookupUri(
  88. contact.getContactId(), contact.getLookUpKey()));
  89. if (0 == contact.getPhotoId()) {
  90. holder.quickContactBadge.setImageResource(R.drawable.touxiang);
  91. } else {
  92. Uri uri = ContentUris.withAppendedId(
  93. ContactsContract.Contacts.CONTENT_URI,
  94. contact.getContactId());
  95. InputStream input = ContactsContract.Contacts
  96. .openContactPhotoInputStream(ctx.getContentResolver(), uri);
  97. Bitmap contactPhoto = BitmapFactory.decodeStream(input);
  98. holder.quickContactBadge.setImageBitmap(contactPhoto);
  99. }
  100. // 当前字母
  101. String currentStr = getAlpha(contact.getSortKey());
  102. // 前面的字母
  103. String previewStr = (position - 1) >= 0 ? getAlpha(list.get(
  104. position - 1).getSortKey()) : " ";
  105. if (!previewStr.equals(currentStr)) {
  106. holder.alpha.setVisibility(View.VISIBLE);
  107. holder.alpha.setText(currentStr);
  108. } else {
  109. holder.alpha.setVisibility(View.GONE);
  110. }
  111. return convertView;
  112. }
  113. private static class ViewHolder {
  114. QuickContactBadge quickContactBadge;
  115. TextView alpha;
  116. TextView name;
  117. TextView number;
  118. }
  119. /**
  120. * 获取首字母
  121. *
  122. * @param str
  123. * @return
  124. */
  125. private String getAlpha(String str) {
  126. if (str == null) {
  127. return "#";
  128. }
  129. if (str.trim().length() == 0) {
  130. return "#";
  131. }
  132. char c = str.trim().substring(0, 1).charAt(0);
  133. // 正则表达式匹配
  134. Pattern pattern = Pattern.compile("^[A-Za-z]+$");
  135. if (pattern.matcher(c + "").matches()) {
  136. return (c + "").toUpperCase(); // 将小写字母转换为大写
  137. } else {
  138. return "#";
  139. }
  140. }
  141. }
/Contact_Demo/src/com/suntek/contact/ContactListActivity.java 
  1. package com.suntek.contact;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import java.util.Map;
  6. import android.app.Activity;
  7. import android.content.AsyncQueryHandler;
  8. import android.content.ContentResolver;
  9. import android.database.Cursor;
  10. import android.net.Uri;
  11. import android.os.Bundle;
  12. import android.provider.ContactsContract;
  13. import android.view.View;
  14. import android.widget.ListView;
  15. import com.suntek.contact.adapter.ContactListAdapter;
  16. import com.suntek.contact.model.ContactBean;
  17. import com.suntek.contact.view.QuickAlphabeticBar;
  18. /**
  19. * 联系人列表
  20. *
  21. * @author Administrator
  22. *
  23. */
  24. public class ContactListActivity extends Activity {
  25. private ContactListAdapter adapter;
  26. private ListView contactList;
  27. private List<ContactBean> list;
  28. private AsyncQueryHandler asyncQueryHandler; // 异步查询数据库类对象
  29. private QuickAlphabeticBar alphabeticBar; // 快速索引条
  30. private Map<Integer, ContactBean> contactIdMap = null;
  31. @Override
  32. protected void onCreate(Bundle savedInstanceState) {
  33. super.onCreate(savedInstanceState);
  34. setContentView(R.layout.contact_list_view);
  35. contactList = (ListView) findViewById(R.id.contact_list);
  36. alphabeticBar = (QuickAlphabeticBar) findViewById(R.id.fast_scroller);
  37. // 实例化
  38. asyncQueryHandler = new MyAsyncQueryHandler(getContentResolver());
  39. init();
  40. }
  41. /**
  42. * 初始化数据库查询参数
  43. */
  44. private void init() {
  45. Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI; // 联系人Uri;
  46. // 查询的字段
  47. String[] projection = { ContactsContract.CommonDataKinds.Phone._ID,
  48. ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
  49. ContactsContract.CommonDataKinds.Phone.DATA1, "sort_key",
  50. ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
  51. ContactsContract.CommonDataKinds.Phone.PHOTO_ID,
  52. ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY };
  53. // 按照sort_key升序查詢
  54. asyncQueryHandler.startQuery(0, null, uri, projection, null, null,
  55. "sort_key COLLATE LOCALIZED asc");
  56. }
  57. /**
  58. *
  59. * @author Administrator
  60. *
  61. */
  62. private class MyAsyncQueryHandler extends AsyncQueryHandler {
  63. public MyAsyncQueryHandler(ContentResolver cr) {
  64. super(cr);
  65. }
  66. @Override
  67. protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
  68. if (cursor != null && cursor.getCount() > 0) {
  69. contactIdMap = new HashMap<Integer, ContactBean>();
  70. list = new ArrayList<ContactBean>();
  71. cursor.moveToFirst(); // 游标移动到第一项
  72. for (int i = 0; i < cursor.getCount(); i++) {
  73. cursor.moveToPosition(i);
  74. String name = cursor.getString(1);
  75. String number = cursor.getString(2);
  76. String sortKey = cursor.getString(3);
  77. int contactId = cursor.getInt(4);
  78. Long photoId = cursor.getLong(5);
  79. String lookUpKey = cursor.getString(6);
  80. if (contactIdMap.containsKey(contactId)) {
  81. // 无操作
  82. } else {
  83. // 创建联系人对象
  84. ContactBean contact = new ContactBean();
  85. contact.setDesplayName(name);
  86. contact.setPhoneNum(number);
  87. contact.setSortKey(sortKey);
  88. contact.setPhotoId(photoId);
  89. contact.setLookUpKey(lookUpKey);
  90. list.add(contact);
  91. contactIdMap.put(contactId, contact);
  92. }
  93. }
  94. if (list.size() > 0) {
  95. setAdapter(list);
  96. }
  97. }
  98. super.onQueryComplete(token, cookie, cursor);
  99. }
  100. }
  101. private void setAdapter(List<ContactBean> list) {
  102. adapter = new ContactListAdapter(this, list, alphabeticBar);
  103. contactList.setAdapter(adapter);
  104. alphabeticBar.init(ContactListActivity.this);
  105. alphabeticBar.setListView(contactList);
  106. alphabeticBar.setHight(alphabeticBar.getHeight());
  107. alphabeticBar.setVisibility(View.VISIBLE);
  108. }
  109. }
自定义组件: 
  1. package com.suntek.contact.view;
  2. import android.content.Context;
  3. import android.util.AttributeSet;
  4. import android.view.MotionEvent;
  5. import android.widget.LinearLayout;
  6. public class SlidingLinearLayout extends LinearLayout {
  7. public SlidingLinearLayout(Context context, AttributeSet attrs) {
  8. super(context, attrs);
  9. }
  10. @Override
  11. public boolean onInterceptTouchEvent(MotionEvent ev) {
  12. return super.onInterceptTouchEvent(ev);
  13. }
  14. }
/Contact_Demo/src/com/suntek/contact/view/QuickAlphabeticBar.java 
  1. package com.suntek.contact.view;
  2. import java.util.HashMap;
  3. import android.app.Activity;
  4. import android.content.Context;
  5. import android.graphics.Canvas;
  6. import android.graphics.Color;
  7. import android.graphics.Paint;
  8. import android.graphics.Typeface;
  9. import android.os.Handler;
  10. import android.util.AttributeSet;
  11. import android.view.MotionEvent;
  12. import android.view.View;
  13. import android.widget.ImageButton;
  14. import android.widget.ListView;
  15. import android.widget.TextView;
  16. import com.suntek.contact.R;
  17. /**
  18. * 字母索引条
  19. *
  20. * @author Administrator
  21. *
  22. */
  23. public class QuickAlphabeticBar extends ImageButton {
  24. private TextView mDialogText; // 中间显示字母的文本框
  25. private Handler mHandler; // 处理UI的句柄
  26. private ListView mList; // 列表
  27. private float mHight; // 高度
  28. // 字母列表索引
  29. private String[] letters = new String[] { "#", "A", "B", "C", "D", "E",
  30. "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
  31. "S", "T", "U", "V", "W", "X", "Y", "Z" };
  32. // 字母索引哈希表
  33. private HashMap<String, Integer> alphaIndexer;
  34. Paint paint = new Paint();
  35. boolean showBkg = false;
  36. int choose = -1;
  37. public QuickAlphabeticBar(Context context) {
  38. super(context);
  39. }
  40. public QuickAlphabeticBar(Context context, AttributeSet attrs, int defStyle) {
  41. super(context, attrs, defStyle);
  42. }
  43. public QuickAlphabeticBar(Context context, AttributeSet attrs) {
  44. super(context, attrs);
  45. }
  46. // 初始化
  47. public void init(Activity ctx) {
  48. mDialogText = (TextView) ctx.findViewById(R.id.fast_position);
  49. mDialogText.setVisibility(View.INVISIBLE);
  50. mHandler = new Handler();
  51. }
  52. // 设置需要索引的列表
  53. public void setListView(ListView mList) {
  54. this.mList = mList;
  55. }
  56. // 设置字母索引哈希表
  57. public void setAlphaIndexer(HashMap<String, Integer> alphaIndexer) {
  58. this.alphaIndexer = alphaIndexer;
  59. }
  60. // 设置字母索引条的高度
  61. public void setHight(float mHight) {
  62. this.mHight = mHight;
  63. }
  64. @Override
  65. public boolean onTouchEvent(MotionEvent event) {
  66. int act = event.getAction();
  67. float y = event.getY();
  68. final int oldChoose = choose;
  69. // 计算手指位置,找到对应的段,让mList移动段开头的位置上
  70. int selectIndex = (int) (y / (mHight / letters.length));
  71. if (selectIndex > -1 && selectIndex < letters.length) { // 防止越界
  72. String key = letters[selectIndex];
  73. if (alphaIndexer.containsKey(key)) {
  74. int pos = alphaIndexer.get(key);
  75. if (mList.getHeaderViewsCount() > 0) { // 防止ListView有标题栏,本例中没有
  76. this.mList.setSelectionFromTop(
  77. pos + mList.getHeaderViewsCount(), 0);
  78. } else {
  79. this.mList.setSelectionFromTop(pos, 0);
  80. }
  81. mDialogText.setText(letters[selectIndex]);
  82. }
  83. }
  84. switch (act) {
  85. case MotionEvent.ACTION_DOWN:
  86. showBkg = true;
  87. if (oldChoose != selectIndex) {
  88. if (selectIndex > 0 && selectIndex < letters.length) {
  89. choose = selectIndex;
  90. invalidate();
  91. }
  92. }
  93. if (mHandler != null) {
  94. mHandler.post(new Runnable() {
  95. @Override
  96. public void run() {
  97. if (mDialogText != null
  98. && mDialogText.getVisibility() == View.INVISIBLE) {
  99. mDialogText.setVisibility(VISIBLE);
  100. }
  101. }
  102. });
  103. }
  104. break;
  105. case MotionEvent.ACTION_MOVE:
  106. if (oldChoose != selectIndex) {
  107. if (selectIndex > 0 && selectIndex < letters.length) {
  108. choose = selectIndex;
  109. invalidate();
  110. }
  111. }
  112. break;
  113. case MotionEvent.ACTION_UP:
  114. showBkg = false;
  115. choose = -1;
  116. if (mHandler != null) {
  117. mHandler.post(new Runnable() {
  118. @Override
  119. public void run() {
  120. if (mDialogText != null
  121. && mDialogText.getVisibility() == View.VISIBLE) {
  122. mDialogText.setVisibility(INVISIBLE);
  123. }
  124. }
  125. });
  126. }
  127. break;
  128. default:
  129. break;
  130. }
  131. return super.onTouchEvent(event);
  132. }
  133. @Override
  134. protected void onDraw(Canvas canvas) {
  135. super.onDraw(canvas);
  136. int height = getHeight();
  137. int width = getWidth();
  138. int sigleHeight = height / letters.length; // 单个字母占的高度
  139. for (int i = 0; i < letters.length; i++) {
  140. paint.setColor(Color.WHITE);
  141. paint.setTextSize(20);
  142. paint.setTypeface(Typeface.DEFAULT_BOLD);
  143. paint.setAntiAlias(true);
  144. if (i == choose) {
  145. paint.setColor(Color.parseColor("#00BFFF")); // 滑动时按下字母颜色
  146. paint.setFakeBoldText(true);
  147. }
  148. // 绘画的位置
  149. float xPos = width / 2 - paint.measureText(letters[i]) / 2;
  150. float yPos = sigleHeight * i + sigleHeight;
  151. canvas.drawText(letters[i], xPos, yPos, paint);
  152. paint.reset();
  153. }
  154. }
  155. }
上一篇:【Android Developers Training】 99. 获取联系人详细信息


下一篇:Android 手机卫士--获取联系人信息并显示与回显