Android通讯录管理(获取联系人、通话记录、短信消息)
2014年2月26日 通讯录开发研究学习
前言:前阵子主要是记录了如何对联系人的一些操作,比如搜索,全选、反选和删除等在实际开发中可能需要实现的功能,本篇博客是小巫从一个别人开源的一个项目抽取出来的部分内容,把它给简化出来,可以让需要的朋友清楚知道如何对Android数据库操作,异步查询数据库获取我们需要的内容。由于内容比较多,我将分三篇博客来讲述获取联系人、通话记录、短信消息的实现。
也许你根本就没耐心看,源码在这里http://download.csdn.net/detail/wwj_748/6962865,骚年去下吧。
上面的是获取联系人的界面效果,实现分组显示联系人,快速索引条查找联系人,下面是实现:
从权限开始:
<!-- 读联系*限 --> <uses-permission android:name="android.permission.READ_CONTACTS" /> <!-- 写联系*限 --> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <!-- 拨号权限 --> <uses-permission android:name="android.permission.CALL_PHONE" /> <!-- 读短信权限 --> <uses-permission android:name="android.permission.READ_SMS" />
界面布局:
/Contact_Demo/res/layout/contact_list_view.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/contact_list_view" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000000" > <com.suntek.contact.view.SlidingLinearLayout android:id="@+id/slidingview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentTop="true" > <ListView android:id="@+id/contact_list" android:layout_width="match_parent" android:layout_height="match_parent" android:cacheColorHint="#000000" android:divider="#00000000" android:fadingEdge="none" android:scrollbars="none" android:scrollingCache="false" android:visibility="visible" /> </com.suntek.contact.view.SlidingLinearLayout> <com.suntek.contact.view.QuickAlphabeticBar android:id="@+id/fast_scroller" android:layout_width="22dp" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_gravity="top|right|center" android:layout_marginTop="0dip" android:background="@null" android:scaleType="centerInside" android:src="@drawable/dic_background" > </com.suntek.contact.view.QuickAlphabeticBar> <TextView android:id="@+id/fast_position" android:layout_width="70dip" android:layout_height="70dip" android:layout_centerInParent="true" android:layout_gravity="center_horizontal|top" android:layout_margin="34dip" android:background="@drawable/sort_icon_bg_click" android:gravity="center" android:padding="2dip" android:textColor="#404040" android:textSize="48dip" android:visibility="invisible" /> </RelativeLayout>
/Contact_Demo/res/layout/contact_list_item.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" > <!-- 首字母 --> <TextView android:id="@+id/alpha" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#333333" android:paddingLeft="10dip" android:textColor="#FFFFFF" android:visibility="gone" /> <!-- 联系人信息 --> <QuickContactBadge android:id="@+id/qcb" android:layout_width="75dip" android:layout_height="75dip" android:layout_alignParentLeft="true" android:layout_below="@+id/alpha" android:layout_marginBottom="3dip" android:layout_marginTop="3dip" android:src="@drawable/touxiang" /> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="5.0dip" android:layout_toRightOf="@+id/qcb" android:singleLine="true" android:textAppearance="?android:textAppearanceLarge" android:textColor="#FFFFFF" /> <TextView android:id="@+id/number" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginLeft="5.0dip" android:layout_toRightOf="@+id/qcb" android:singleLine="true" android:textAppearance="?android:textAppearanceSmall" android:textColor="#FFFFFF" /> </RelativeLayout>
代码实现:
1. 先定义一个实体类,用来保存联系人信息
/Contact_Demo/src/com/suntek/contact/model/ContactBean.java
package com.suntek.contact.model; public class ContactBean { private int contactId; //id private String desplayName;//姓名 private String phoneNum; // 电话号码 private String sortKey; // 排序用的 private Long photoId; // 图片id private String lookUpKey; private int selected = 0; private String formattedNumber; private String pinyin; // 姓名拼音 public int getContactId() { return contactId; } public void setContactId(int contactId) { this.contactId = contactId; } public String getDesplayName() { return desplayName; } public void setDesplayName(String desplayName) { this.desplayName = desplayName; } public String getPhoneNum() { return phoneNum; } public void setPhoneNum(String phoneNum) { this.phoneNum = phoneNum; } public String getSortKey() { return sortKey; } public void setSortKey(String sortKey) { this.sortKey = sortKey; } public Long getPhotoId() { return photoId; } public void setPhotoId(Long photoId) { this.photoId = photoId; } public String getLookUpKey() { return lookUpKey; } public void setLookUpKey(String lookUpKey) { this.lookUpKey = lookUpKey; } public int getSelected() { return selected; } public void setSelected(int selected) { this.selected = selected; } public String getFormattedNumber() { return formattedNumber; } public void setFormattedNumber(String formattedNumber) { this.formattedNumber = formattedNumber; } public String getPinyin() { return pinyin; } public void setPinyin(String pinyin) { this.pinyin = pinyin; } }
适配器:
/Contact_Demo/src/com/suntek/contact/adapter/ContactListAdapter.java
package com.suntek.contact.adapter; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import android.content.ContentUris; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.QuickContactBadge; import android.widget.TextView; import com.suntek.contact.R; import com.suntek.contact.model.ContactBean; import com.suntek.contact.view.QuickAlphabeticBar; public class ContactListAdapter extends BaseAdapter { private LayoutInflater inflater; private List<ContactBean> list; private HashMap<String, Integer> alphaIndexer; // 字母索引 private String[] sections; // 存储每个章节 private Context ctx; // 上下文 public ContactListAdapter(Context context, List<ContactBean> list, QuickAlphabeticBar alpha) { this.ctx = context; this.inflater = LayoutInflater.from(context); this.list = list; this.alphaIndexer = new HashMap<String, Integer>(); this.sections = new String[list.size()]; for (int i = 0; i < list.size(); i++) { // 得到字母 String name = getAlpha(list.get(i).getSortKey()); if (!alphaIndexer.containsKey(name)) { alphaIndexer.put(name, i); } } Set<String> sectionLetters = alphaIndexer.keySet(); ArrayList<String> sectionList = new ArrayList<String>(sectionLetters); Collections.sort(sectionList); // 根据首字母进行排序 sections = new String[sectionList.size()]; sectionList.toArray(sections); alpha.setAlphaIndexer(alphaIndexer); } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } public void remove(int position) { list.remove(position); } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = inflater.inflate(R.layout.contact_list_item, null); holder = new ViewHolder(); holder.quickContactBadge = (QuickContactBadge) convertView .findViewById(R.id.qcb); holder.alpha = (TextView) convertView.findViewById(R.id.alpha); holder.name = (TextView) convertView.findViewById(R.id.name); holder.number = (TextView) convertView.findViewById(R.id.number); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } ContactBean contact = list.get(position); String name = contact.getDesplayName(); String number = contact.getPhoneNum(); holder.name.setText(name); holder.number.setText(number); holder.quickContactBadge.assignContactUri(Contacts.getLookupUri( contact.getContactId(), contact.getLookUpKey())); if (0 == contact.getPhotoId()) { holder.quickContactBadge.setImageResource(R.drawable.touxiang); } else { Uri uri = ContentUris.withAppendedId( ContactsContract.Contacts.CONTENT_URI, contact.getContactId()); InputStream input = ContactsContract.Contacts .openContactPhotoInputStream(ctx.getContentResolver(), uri); Bitmap contactPhoto = BitmapFactory.decodeStream(input); holder.quickContactBadge.setImageBitmap(contactPhoto); } // 当前字母 String currentStr = getAlpha(contact.getSortKey()); // 前面的字母 String previewStr = (position - 1) >= 0 ? getAlpha(list.get( position - 1).getSortKey()) : " "; if (!previewStr.equals(currentStr)) { holder.alpha.setVisibility(View.VISIBLE); holder.alpha.setText(currentStr); } else { holder.alpha.setVisibility(View.GONE); } return convertView; } private static class ViewHolder { QuickContactBadge quickContactBadge; TextView alpha; TextView name; TextView number; } /** * 获取首字母 * * @param str * @return */ private String getAlpha(String str) { if (str == null) { return "#"; } if (str.trim().length() == 0) { return "#"; } char c = str.trim().substring(0, 1).charAt(0); // 正则表达式匹配 Pattern pattern = Pattern.compile("^[A-Za-z]+$"); if (pattern.matcher(c + "").matches()) { return (c + "").toUpperCase(); // 将小写字母转换为大写 } else { return "#"; } } }
/Contact_Demo/src/com/suntek/contact/ContactListActivity.java
package com.suntek.contact; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import android.app.Activity; import android.content.AsyncQueryHandler; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.ContactsContract; import android.view.View; import android.widget.ListView; import com.suntek.contact.adapter.ContactListAdapter; import com.suntek.contact.model.ContactBean; import com.suntek.contact.view.QuickAlphabeticBar; /** * 联系人列表 * * @author Administrator * */ public class ContactListActivity extends Activity { private ContactListAdapter adapter; private ListView contactList; private List<ContactBean> list; private AsyncQueryHandler asyncQueryHandler; // 异步查询数据库类对象 private QuickAlphabeticBar alphabeticBar; // 快速索引条 private Map<Integer, ContactBean> contactIdMap = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.contact_list_view); contactList = (ListView) findViewById(R.id.contact_list); alphabeticBar = (QuickAlphabeticBar) findViewById(R.id.fast_scroller); // 实例化 asyncQueryHandler = new MyAsyncQueryHandler(getContentResolver()); init(); } /** * 初始化数据库查询参数 */ private void init() { Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI; // 联系人Uri; // 查询的字段 String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.DATA1, "sort_key", ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.PHOTO_ID, ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY }; // 按照sort_key升序查詢 asyncQueryHandler.startQuery(0, null, uri, projection, null, null, "sort_key COLLATE LOCALIZED asc"); } /** * * @author Administrator * */ private class MyAsyncQueryHandler extends AsyncQueryHandler { public MyAsyncQueryHandler(ContentResolver cr) { super(cr); } @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { if (cursor != null && cursor.getCount() > 0) { contactIdMap = new HashMap<Integer, ContactBean>(); list = new ArrayList<ContactBean>(); cursor.moveToFirst(); // 游标移动到第一项 for (int i = 0; i < cursor.getCount(); i++) { cursor.moveToPosition(i); String name = cursor.getString(1); String number = cursor.getString(2); String sortKey = cursor.getString(3); int contactId = cursor.getInt(4); Long photoId = cursor.getLong(5); String lookUpKey = cursor.getString(6); if (contactIdMap.containsKey(contactId)) { // 无操作 } else { // 创建联系人对象 ContactBean contact = new ContactBean(); contact.setDesplayName(name); contact.setPhoneNum(number); contact.setSortKey(sortKey); contact.setPhotoId(photoId); contact.setLookUpKey(lookUpKey); list.add(contact); contactIdMap.put(contactId, contact); } } if (list.size() > 0) { setAdapter(list); } } super.onQueryComplete(token, cookie, cursor); } } private void setAdapter(List<ContactBean> list) { adapter = new ContactListAdapter(this, list, alphabeticBar); contactList.setAdapter(adapter); alphabeticBar.init(ContactListActivity.this); alphabeticBar.setListView(contactList); alphabeticBar.setHight(alphabeticBar.getHeight()); alphabeticBar.setVisibility(View.VISIBLE); } }
自定义组件:
package com.suntek.contact.view; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.LinearLayout; public class SlidingLinearLayout extends LinearLayout { public SlidingLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); } }
/Contact_Demo/src/com/suntek/contact/view/QuickAlphabeticBar.java
package com.suntek.contact.view; import java.util.HashMap; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.os.Handler; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.ImageButton; import android.widget.ListView; import android.widget.TextView; import com.suntek.contact.R; /** * 字母索引条 * * @author Administrator * */ public class QuickAlphabeticBar extends ImageButton { private TextView mDialogText; // 中间显示字母的文本框 private Handler mHandler; // 处理UI的句柄 private ListView mList; // 列表 private float mHight; // 高度 // 字母列表索引 private String[] letters = new String[] { "#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }; // 字母索引哈希表 private HashMap<String, Integer> alphaIndexer; Paint paint = new Paint(); boolean showBkg = false; int choose = -1; public QuickAlphabeticBar(Context context) { super(context); } public QuickAlphabeticBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public QuickAlphabeticBar(Context context, AttributeSet attrs) { super(context, attrs); } // 初始化 public void init(Activity ctx) { mDialogText = (TextView) ctx.findViewById(R.id.fast_position); mDialogText.setVisibility(View.INVISIBLE); mHandler = new Handler(); } // 设置需要索引的列表 public void setListView(ListView mList) { this.mList = mList; } // 设置字母索引哈希表 public void setAlphaIndexer(HashMap<String, Integer> alphaIndexer) { this.alphaIndexer = alphaIndexer; } // 设置字母索引条的高度 public void setHight(float mHight) { this.mHight = mHight; } @Override public boolean onTouchEvent(MotionEvent event) { int act = event.getAction(); float y = event.getY(); final int oldChoose = choose; // 计算手指位置,找到对应的段,让mList移动段开头的位置上 int selectIndex = (int) (y / (mHight / letters.length)); if (selectIndex > -1 && selectIndex < letters.length) { // 防止越界 String key = letters[selectIndex]; if (alphaIndexer.containsKey(key)) { int pos = alphaIndexer.get(key); if (mList.getHeaderViewsCount() > 0) { // 防止ListView有标题栏,本例中没有 this.mList.setSelectionFromTop( pos + mList.getHeaderViewsCount(), 0); } else { this.mList.setSelectionFromTop(pos, 0); } mDialogText.setText(letters[selectIndex]); } } switch (act) { case MotionEvent.ACTION_DOWN: showBkg = true; if (oldChoose != selectIndex) { if (selectIndex > 0 && selectIndex < letters.length) { choose = selectIndex; invalidate(); } } if (mHandler != null) { mHandler.post(new Runnable() { @Override public void run() { if (mDialogText != null && mDialogText.getVisibility() == View.INVISIBLE) { mDialogText.setVisibility(VISIBLE); } } }); } break; case MotionEvent.ACTION_MOVE: if (oldChoose != selectIndex) { if (selectIndex > 0 && selectIndex < letters.length) { choose = selectIndex; invalidate(); } } break; case MotionEvent.ACTION_UP: showBkg = false; choose = -1; if (mHandler != null) { mHandler.post(new Runnable() { @Override public void run() { if (mDialogText != null && mDialogText.getVisibility() == View.VISIBLE) { mDialogText.setVisibility(INVISIBLE); } } }); } break; default: break; } return super.onTouchEvent(event); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int height = getHeight(); int width = getWidth(); int sigleHeight = height / letters.length; // 单个字母占的高度 for (int i = 0; i < letters.length; i++) { paint.setColor(Color.WHITE); paint.setTextSize(20); paint.setTypeface(Typeface.DEFAULT_BOLD); paint.setAntiAlias(true); if (i == choose) { paint.setColor(Color.parseColor("#00BFFF")); // 滑动时按下字母颜色 paint.setFakeBoldText(true); } // 绘画的位置 float xPos = width / 2 - paint.measureText(letters[i]) / 2; float yPos = sigleHeight * i + sigleHeight; canvas.drawText(letters[i], xPos, yPos, paint); paint.reset(); } } }