Android訪問和載入本地聯絡人的程式碼實現

投稿發表於2015-03-07

在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"/>

相關文章