[android] 01_读取系统联系人

Android 4.0

读取系统联系人

1、系统中联系人contacts的数据库保存在:

/data/data/com.android.providers.contacts/databases/contacts2.db

2、查看源码,可以知道contacts的authorities(分号表示两个名字都可以)

android:authorities="contacts;com.android.contacts"

3、查看源码,在ContactsProvider2.java中ctrl+F,输入UriMatcher。

matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);

4、联系人中3个表主要字段之间的关系:

一、读取系统联系人(利用ContentProvider内容提供者)

1、先读取raw_contacts表,将联系人id(contact_id)给读取出来

2、再通过这个cursor,从表data,将数据给读取出来

注意:读取的不是data表,而是raw_contacts表和data表的视图,在data表中mimetype_id在该视图中为mimetype,而不是mimetype_id,否则会报错

3、将读取出来的每个联系人封装到一个javabean中去,再加入到List集合中

4、将List集合中的每一个联系人,用一个ListView给显示出来

步骤:

1、定义布局

a) 定义主界面

b) 定义ListView界面

2、创建内容提供者

3、写程序

二、核心代码

MainActivity.java
 
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import cn.zengfansheng.domain.ContactInfo;
import cn.zengfansheng.service.ContactInfoProvider;
 
public class MainActivity extends Activity {
    private ListView lV;
    private List<ContactInfo> allContacts;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lV = (ListView) this.findViewById(R.id.lv_contacts);
    }
    /**
     * 点击按钮获取全部系统联系人信息
     * 
     * @param view
     */
    public void getSysContacts(View view) {
        allContacts = ContactInfoProvider.getAllContacts(this);
        lV.setAdapter(new MyAdapter());
    }
    private class MyAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            return allContacts.size();
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            
            View view = View.inflate(MainActivity.this, R.layout.list_contactsnull);
            TextView tv_name = (TextView) view.findViewById(R.id.tv_name);
            TextView tv_email = (TextView) view.findViewById(R.id.tv_email);
            TextView tv_phone = (TextView) view.findViewById(R.id.tv_phone);
            
            ContactInfo contactInfo = allContacts.get(position);
            tv_name.setText(contactInfo.getName());
            tv_email.setText(contactInfo.getEmail());
            tv_phone.setText(contactInfo.getPhone());
            
            return view;
            // return null;// 问题2:
        }
        @Override
        public Object getItem(int position) {
            return null;
        }
        @Override
        public long getItemId(int position) {
            return 0;
        }
    }
}
-------------------------------------
ContactInfoProvider.java 内容提供者
import java.util.ArrayList;
import java.util.List;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import cn.zengfansheng.domain.ContactInfo;
 
public class ContactInfoProvider {
    /**
     * 获取系统全部联系人
     * 
     * @param context
     * @return
     */
    public static List<ContactInfo> getAllContacts(Context context) {
 
        List<ContactInfo> lInfos = new ArrayList<ContactInfo>();
 
        // 1、从表raw_contacts中获取所有的联系人id(contact_id)
        ContentResolver resolver = context.getContentResolver();
 
        Uri contactUri = Uri.parse("content://com.android.contacts/raw_contacts");
        Uri dataUri = Uri.parse("content://com.android.contacts/data");
 
        Cursor contactcursor = resolver.query(contactUri, new String[] { "contact_id" }, nullnullnull);
 
        while (contactcursor.moveToNext()) {
 
            String contactId = contactcursor.getString(0);// 0列是建立在参数二选择列表之上的
 
            ContactInfo contactInfo = new ContactInfo();
 
         if (contactId != null) { // 问题3:防止删除联系人,报异常
 
            // 2、根据contactId从data表中获取数据
            Cursor datacursor = resolver.query(dataUri, null"raw_contact_id=?"new String[]{contactId}, null);
            while (datacursor.moveToNext()) {
 
                String data1 = datacursor.getString(datacursor.getColumnIndex("data1"));
                String mimetype = datacursor.getString(datacursor.getColumnIndex("mimetype"));
 
//                String mimetype = datacursor.getString(datacursor.getColumnIndex("mimetype_id"));
                // 问题1:其实不是data表,是data表和raw_contacts表的视图,不是mimetype_id而是mimetype,可以通过下面的语句
                /*String[] columnNames = datacursor.getColumnNames();
                for (String string : columnNames) {
                    System.out.println(string);
                }*/
 
                if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {
                    contactInfo.setEmail(data1);
                } else if ("vnd.android.cursor.item/name".equals(mimetype)) {
                    contactInfo.setName(data1);
                } else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
                    contactInfo.setPhone(data1);
                }
                System.out.println("-------------------");
            }
         }
            lInfos.add(contactInfo);
        }
        return lInfos;
    }
}

结果:

问题1:权限

android.permission.READ_CONTACTS

问题2:mimetype_id不存在,找的不是data表,其实是raw_contacts表和data表合并的视图,而该视图不存在mimetype_id,因为改了名字为mimetype,

技巧:判断列是什么名字,可以cursor.getColumnNames(),然后打印出来看下。

String[] columnNames = datacursor.getColumnNames();
    for (String string : columnNames) {
    System.out.println(string);
}

问题3:ListView中getView()方法返回view对象时,写得是null,报的空指针访问异常。特殊。

问题4:当删除联系人时,再开启程序,会报异常,这是因为android删除联系人时,不是将这条记录给删除,

而是将其置为了null,这主要是为了给同步到gmail方便,只要扫描那些为null,就删除,这是一个bug。

但还是占用一个格子。