在Android开发中,我们经常会遇到访问和加载本地联系人的情况,毕竟手机中联系人是最重要的数据之一,很多手机应用都会需要手机联系人的信息,比如姓名、手机号码等。本文通过一个简单的例子以及Android代码,来实现一个本地联系人加载读取的功能。
首先先建布局文件,界面很简单,就是一个搜索框和下面的联系人列表:
<?xml version="1.0"encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FFD3D7DF" android:orientation="vertical" android:padding="0dip"> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="3dip" android:layout_marginRight="3dip" android:layout_marginTop="3dip"> <EditText android:id="@+id/search_view" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="@string/hint_search_contacts" android:paddingLeft="32dip" android:singleLine="true" android:textSize="16sp"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/search_view" android:layout_centerVertical="true" android:layout_marginLeft="3dip" android:src="@drawable/contacts"/> </RelativeLayout> <ListView android:id="@+id/contact_list" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="0dip" android:layout_marginLeft="0dip" android:layout_marginRight="0dip" android:layout_marginTop="0dip" android:layout_weight="1.0" android:cacheColorHint="#00000000" android:divider="#00000000" android:dividerHeight="0.1px" android:fadingEdge="none" android:footerDividersEnabled="false" android:listSelector="@null" android:paddingBottom="0dip" android:paddingLeft="0dip" android:paddingRight="0dip" android:paddingTop="0dip"/> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?>? <LinearLayout? xmlns:android="http://schemas.android.com/apk/res/android"? android:orientation="horizontal"? android:layout_height="wrap_content"? android:layout_width="fill_parent"? android:paddingTop="2dip"? android:paddingBottom="2dip"? android:background="@color/list_item_background">? <ImageView? android:id="@+id/photo"? android:layout_height="wrap_content"? android:layout_width="wrap_content"? android:layout_marginLeft="5dip"? android:layout_gravity="center_vertical"? android:layout_weight="1"? android:src="@drawable/default_avatar"? />? <LinearLayout? android:orientation="vertical"? android:layout_height="wrap_content"? android:layout_width="wrap_content"? android:layout_gravity="center_vertical"? android:layout_marginLeft="5dip"? android:layout_weight="100">? <TextView android:id="@+id/text1"? android:typeface="serif"? android:singleLine="true"? style="@style/list_font_main_text" />? <LinearLayout? android:orientation="horizontal"? android:layout_height="wrap_content"? android:layout_width="wrap_content"? android:layout_marginTop="3dip">? <TextView android:id="@+id/text2"? android:typeface="serif"? android:singleLine="true"? style="@style/list_font_detail_text" />? <TextView android:id="@+id/text3"? android:ellipsize="marquee"? android:layout_marginLeft="3dip"? android:marqueeRepeatLimit="marquee_forever"? android:scrollHorizontally="true"? style="@style/list_font_detail_text" />? </LinearLayout>? </LinearLayout>? </LinearLayout>
然后是点击事件:(点击后要把选择的联系人号码返回到输入框里)
// 获取联系人按钮对象并绑定onClick单击事件? phoneButton = (Button) findViewById(R.id.find_phone);? phoneButton.setOnClickListener(new OnClickListener() {? public void onClick(View v) {? // 从联系人选择号码,再通过onActivityResult()方法处理回调结果? Intent intent = new Intent(context, ContactsActivity.class);? startActivityForResult(intent, REQUEST_CODE);? }? });? /**? * 选择联系人的回调处理函数? */? @Override? public void onActivityResult(int reqCode, int resultCode, Intent data) {? super.onActivityResult(reqCode, resultCode, data);? if (resultCode == RESULT_OK) {? switch (reqCode) {? case REQUEST_CODE:? String phone = data.getStringExtra("phone");? phoneEditText.setText(phone);? break;? }? }? }
下面就是联系人界面的activity了:
/**? * 显示用户手机上的联系人? *? * @author Mr.Z? * @time 2012-3-21? *? */? public class ContactsActivity extends Activity {? private Context ctx = ContactsActivity.this;? private TextView topTitleTextView;? private ListView listView = null;? List<HashMap<String, String>> contactsList = null;? private EditText contactsSearchView;? private ProgressDialog progressDialog = null;? // 数据加载完成的消息? private final int MESSAGE_SUCC_LOAD = 0;? // 数据查询完成的消息? private final int MESSAGE_SUCC_QUERY = 1;? private Handler handler = new Handler() {? @Override? public void handleMessage(Message msg) {? super.handleMessage(msg);? switch (msg.what) {? case MESSAGE_SUCC_LOAD:? listView.setAdapter(new ContactsAdapter(ctx));? progressDialog.dismiss();? break;? case MESSAGE_SUCC_QUERY:? listView.setAdapter(new ContactsAdapter(ctx));? break;? }? }? };? protected void onCreate(Bundle savedInstanceState) {? requestWindowFeature(Window.FEATURE_NO_TITLE);? getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);? super.onCreate(savedInstanceState);? this.setContentView(R.layout.contacts);? // 使用listView显示联系人? listView = (ListView) findViewById(R.id.contact_list);? loadAndSaveContacts();? // 绑定listView item的单击事件? listView.setOnItemClickListener(new OnItemClickListener() {? @SuppressWarnings("unchecked")? public void onItemClick(AdapterView<?> adapterView, View view, int position, long _id) {? HashMap<String, String> map = (HashMap<String, String>) adapterView.getItemAtPosition(position);? String phone = map.get("phone");? // 对手机号码进行预处理(去掉号码前的+86、首尾空格、“-”号等)? phone = phone.replaceAll("^(\\+86)", "");? phone = phone.replaceAll("^(86)", "");? phone = phone.replaceAll("-", "");? phone = phone.trim();? // 如果当前号码并不是手机号码? if (!SaleUtil.isValidPhoneNumber(phone))? SaleUtil.createDialog(ctx, R.string.dialog_title_tip, getString(R.string.alert_contacts_error_phone));? else {? Intent intent = new Intent();? intent.putExtra("phone", phone);? setResult(RESULT_OK, intent);? // 关闭当前窗口? finish();? }? }? });? contactsSearchView = (EditText) findViewById(R.id.search_view);? contactsSearchView.addTextChangedListener(new TextWatcher() {? public void afterTextChanged(Editable s) {? }? public void beforeTextChanged(CharSequence s, int start, int count, int after) {? }? public void onTextChanged(CharSequence s, int start, int before, int count) {? queryContacts(s.toString());? }? });? }? /**? * 加载并存储联系人数据? */? private void loadAndSaveContacts() {? progressDialog = ProgressDialog.show(ctx, null, "正在加载联系人数据...");? new Thread() {? @Override? public void run() {? // 获取联系人数据? contactsList = findContacts();? // 临时存储联系人数据? DBHelper.saveContacts(ctx, contactsList);? // 发送消息通知更新UI? handler.sendEmptyMessage(MESSAGE_SUCC_LOAD);? }? }.start();? }? /**? * 根据条件从本地临时库中获取联系人? *? * @param keyWord 查询关键字? */? private void queryContacts(final String keyWord) {? new Thread() {? @Override? public void run() {? // 获取联系人数据? contactsList = DBHelper.findContactsByCond(ctx, keyWord);? // 发送消息通知更新UI? handler.sendEmptyMessage(MESSAGE_SUCC_QUERY);? }? }.start();? }? /**? * 获取手机联系人信息? *? * @return List<HashMap<String, String>>? */? public List<HashMap<String, String>> findContacts() {? List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();? // 查询联系人? Cursor contactsCursor = ctx.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, PhoneLookup.DISPLAY_NAME + " COLLATE LOCALIZED ASC");? // 姓名的索引? int nameIndex = 0;? // 联系人姓名? String name = null;? // 联系人头像ID? String photoId = null;? // 联系人的ID索引值? String contactsId = null;? // 查询联系人的电话号码? Cursor phoneCursor = null;? while (contactsCursor.moveToNext()) {? nameIndex = contactsCursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);? name = contactsCursor.getString(nameIndex);? photoId = contactsCursor.getString(contactsCursor.getColumnIndex(PhoneLookup.PHOTO_ID));? contactsId = contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.Contacts._ID));? phoneCursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactsId, null, null);? // 遍历联系人号码(一个人对应于多个电话号码)? while (phoneCursor.moveToNext()) {? HashMap<String, String> phoneMap = new HashMap<String, String>();? // 添加联系人姓名? phoneMap.put("name", name);? // 添加联系人头像? phoneMap.put("photo", photoId);? // 添加电话号码? phoneMap.put("phone", phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));? // 添加号码类型(住宅电话、手机号码、单位电话等)? phoneMap.put("type", getString(ContactsContract.CommonDataKinds.Phone.getTypeLabelResource(phoneCursor.getInt(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE))))); list.add(phoneMap);? }? phoneCursor.close();? }? contactsCursor.close();? return list;? }? /**? * 获取联系人头像? *? * @param context 上下文环境? * @param photoId 头像ID? * @return Bitmap? */? public static Bitmap getPhoto(Context context, String photoId) {? Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.default_avatar);? if (photoId != null && "".equals(photoId)) {? String[] projection = new String[] { ContactsContract.Data.DATA15 };? String selection = "ContactsContract.Data._ID = " + photoId;? Cursor cur = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, projection, selection, null, null);? if (cur != null) {? cur.moveToFirst();? byte[] contactIcon = null;? contactIcon = cur.getBlob(cur.getColumnIndex(ContactsContract.Data.DATA15));? if (contactIcon != null) {? bitmap = BitmapFactory.decodeByteArray(contactIcon, 0, contactIcon.length);? }? }? }? return bitmap;? }? /**? * 自定义联系人Adapter? */? class ContactsAdapter extends BaseAdapter {? private LayoutInflater inflater = null;? public ContactsAdapter(Context ctx) {? inflater = LayoutInflater.from(ctx);? }? public int getCount() {? return contactsList.size();? }? public Object getItem(int position) {? return contactsList.get(position);? }? public long getItemId(int position) {? return position;? }? public View getView(int position, View convertView, ViewGroup parent) {? ViewHolder holder = null;? if (convertView == null) {? holder = new ViewHolder();? convertView = inflater.inflate(R.layout.contacts_listview_item, null);? holder.text1 = (TextView) convertView.findViewById(R.id.text1);? holder.text2 = (TextView) convertView.findViewById(R.id.text2);? holder.text3 = (TextView) convertView.findViewById(R.id.text3);? convertView.setTag(holder);? } else {? holder = (ViewHolder) convertView.getTag();? }? holder.text1.setText(contactsList.get(position).get("name"));? holder.text2.setText(contactsList.get(position).get("type"));? holder.text3.setText(contactsList.get(position).get("phone"));? return convertView;? }? public final class ViewHolder {? private TextView text1;? private TextView text2;? private TextView text3;? }? }? }
查询方法语句:
/**? * 根据条件查询联系人数据? *? * @param context 上下文环境? * @param keyWord 查询关键字? * @return List<HashMap<String, String>>? */? public static List<HashMap<String, String>> findContactsByCond(Context context, String keyWord) {? List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();? SQLiteDatabase db = DBHelper.getSQLiteDb(context);? String sql = "select * from contacts where name like '" + keyWord + "%' or name_alias like '" + keyWord + "%' order by _id";? // 查询数据? Cursor cursor = db.rawQuery(sql, null);? while (cursor.moveToNext()) {? HashMap<String, String> map = new HashMap<String, String>();? map.put("name", cursor.getString(cursor.getColumnIndex("name")));? map.put("phone", cursor.getString(cursor.getColumnIndex("phone")));? map.put("type", cursor.getString(cursor.getColumnIndex("type")));? map.put("photo", cursor.getString(cursor.getColumnIndex("photo")));? list.add(map);? }? cursor.close();? db.close();? return list;? }? /**? * 存储联系人信息? *? * @param context 上下文环境? * @param contactsList 联系人列表? */? public static void saveContacts(Context context, List<HashMap<String, String>> contactsList) {? SQLiteDatabase db = DBHelper.getSQLiteDb(context);? // 开启事务控制? db.beginTransaction();? try {? // 先将联系人数据清空? db.execSQL("drop table if exists contacts");? db.execSQL("create table contacts(_id integer not null primary key autoincrement, name varchar(50), name_alias varchar(10), phone varchar(30), type varchar(50), photo varchar(50))");? String sql = null;? for (HashMap<String, String> contactsMap : contactsList) {? sql = String.format("insert into contacts(name,name_alias,phone,type,photo) values('%s','%s','%s','%s','%s')", contactsMap.get("name"), SaleUtil.getPinYinFirstAlphabet(contactsMap.get("name")), contactsMap.get("phone"), contactsMap.get("type"), contactsMap.get("photo"));? db.execSQL(sql);? }? // 设置事务标志为成功? db.setTransactionSuccessful();? } finally {? // 结束事务? db.endTransaction();? db.close();? }? }
工具类:
/**? * 判断客户手机号码是否符合规则? *? * @param userPhone 客户手机号码? * @return true | false? */? public static boolean isValidPhoneNumber(String userPhone) {? if (null == userPhone || "".equals(userPhone))? return false;? Pattern p = Pattern.compile("^0?1[0-9]{10}");? Matcher m = p.matcher(userPhone);? return m.matches();? }? /**? * 获取中文的拼音首字母? *? * @param chinese 中文? * @return 拼音首字母? */? public static String getPinYinFirstAlphabet(String chinese) {? String convert = "";? for (int j = 0; j < chinese.length(); j++) {? char word = chinese.charAt(j);? String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);? if (pinyinArray != null) {? convert += pinyinArray[0].charAt(0);? } else {? convert += word;? }? }? return convert;? }
最后加上权限就行了;
<!-- 访问联系人的权限 --> <uses-permission android:name="android.permission.READ_CONTACTS"/>