在上一篇學習ListView的時候,看到在API中擷取連絡人的例子已經不被官方推薦了。於是,手癢又查了查,看看使用Android如何擷取連絡人資訊。這篇可以說著對ListView繼續深入學習,也是對android中訪問連絡人資訊的學習。
在學習的過程中參考了很多資料,其中寫得比較好的是這一篇http://xys289187120.blog.51cto.com/3361352/656766
我的例子也基本上是模仿他寫的。
下面看代碼
package com.example.contactlist;import java.util.ArrayList;import java.util.List;import android.app.ListActivity;import android.content.Context;import android.database.Cursor;import android.os.Bundle;import android.provider.ContactsContract;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;public class MainActivity extends ListActivity {Context myContext = null;MyListAdapter myListAdapter = null;TextView name = null;TextView number = null;//這兩個List用於暫時儲存連絡人的名字和號碼List myContactName = new ArrayList();List myContactNumber = new ArrayList();public void onCreate(Bundle savedInstanceState) {myContext = this;//使用getContentResolver方法來讀取連絡人的表Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null); while(cursor.moveToNext()){ //連絡人的IDString id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); //連絡人的名稱String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); //連絡人的電話String number = "";//連絡人是否有電話號碼int isHas = Integer.parseInt(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts. HAS_PHONE_NUMBER))); if(isHas>0){ Cursor c = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID+" = " + id,null,null); while(c.moveToNext()){ number += c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))+" "; } c.close(); } myContactName.add(name);myContactNumber.add(number);} cursor.close();myListAdapter = new MyListAdapter(this);setListAdapter(myListAdapter);super.onCreate(savedInstanceState);}//定義一個BaseAdpter的子類,並重寫getView方法class MyListAdapter extends BaseAdapter {public MyListAdapter(Context context){myContext = context;}public int getCount() {// TODO Auto-generated method stubreturn myContactName.size();}public Object getItem(int position) {// TODO Auto-generated method stubreturn position;}public long getItemId(int position) {// TODO Auto-generated method stubreturn position;}public View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubif(convertView == null){//將List布局檔案執行個體化為一個ViewconvertView = LayoutInflater.from(myContext).inflate(R.layout.list, null);name = (TextView) convertView.findViewById(R.id.name);number = (TextView) convertView.findViewById(R.id.number);}name.setText(myContactName.get(position));number.setText(myContactNumber.get(position));return convertView;}}}
相對於前一篇的區別是,這次的代碼中定義了一個BaseAdpter的子類,並重寫了getView方法。
還有一點就是
Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null);
這一句代碼中,我們通過getContentResolver()方法來讀取連絡人資料庫中的內容。getContentResolver可以讀取通過ContentProvider提供的資料。這裡先不細說了。
這個程式運行起來,剛開始是沒問題的,所有的連絡人都讀取出來了。但是,當我向下拖動ListView的時候,發現,有的連絡人的資訊重新整理變成了別的連絡人,有的連絡人順序也變了,總之一拖動ListView就會出現一些比較奇怪的現象。
我把這個問題放到一些論壇上和大家討論了一下。目前個人認為比較靠譜的解釋是我在getView中的寫法會導致Item中的View重新初始化。。所以會導致一些連絡人變了。。(誰有更好的解釋留言告訴我一下)
我試了一種比較好的解決方案就是加上一個靜態類ViewHolder,修改後代碼如下
package com.example.contactlist;import java.util.ArrayList;import java.util.List;import android.app.ListActivity;import android.content.Context;import android.database.Cursor;import android.os.Bundle;import android.provider.ContactsContract;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;public class MainActivity extends ListActivity {Context myContext = null;MyListAdapter myListAdapter = null;ViewHolder viewHolder = null;List myContactName = new ArrayList();List myContactNumber = new ArrayList();public void onCreate(Bundle savedInstanceState) {myContext = this;//使用getContentResolver方法來讀取連絡人的表Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null); while(cursor.moveToNext()){ //連絡人的IDString id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); //連絡人的名稱String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); //連絡人的電話String number = "";//連絡人是否有電話號碼int isHas = Integer.parseInt(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts. HAS_PHONE_NUMBER))); if(isHas>0){ Cursor c = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID+" = " + id,null,null); while(c.moveToNext()){ number += c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))+" "; } c.close(); } myContactName.add(name);myContactNumber.add(number);} cursor.close();myListAdapter = new MyListAdapter(this);setListAdapter(myListAdapter);super.onCreate(savedInstanceState);}class MyListAdapter extends BaseAdapter {public MyListAdapter(Context context){myContext = context;}public int getCount() {// TODO Auto-generated method stubreturn myContactName.size();}public Object getItem(int position) {// TODO Auto-generated method stubreturn position;}public long getItemId(int position) {// TODO Auto-generated method stubreturn position;}public View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubif(convertView == null){viewHolder = new ViewHolder();convertView = LayoutInflater.from(myContext).inflate(R.layout.list, null);viewHolder.name = (TextView) convertView.findViewById(R.id.name);viewHolder.number = (TextView) convertView.findViewById(R.id.number);convertView.setTag(viewHolder);}else { viewHolder = (ViewHolder) convertView.getTag(); }viewHolder.name.setText(myContactName.get(position));viewHolder.number.setText(myContactNumber.get(position));return convertView;}} private static class ViewHolder { TextView name; TextView number; }}
加上了這個類之後,我再試了試發現ListView拖動的時候比較平滑,也沒有出現過連絡人位置改變的情況了。
由於這個涉及到連絡人資訊所以就不了,但是代碼保證是可用的。
附上布局檔案: