1. 程式人生 > >Android進階之讀取手機聯絡人顯示listview並點選撥號(CursorAdapter)

Android進階之讀取手機聯絡人顯示listview並點選撥號(CursorAdapter)

一、CursorAdapter介紹

1、繼承於BaseAdapter是個虛類,它為cursor和ListView提供了連線的橋樑。
如:public abstract class CursorAdapter extends BaseAdapter

2、注意cursor的必須要有個命名為”_id”的列。比如Contacts._ID就為”_id”

3、必須實現以下函式:
①newView(Context context, Cursor cursor, ViewGroup parent)
newView:並不是每次都被呼叫的,它只在例項化的時候呼叫,資料增加的時候也會呼叫,但是在重繪(比如修改條目裡的TextView的內容)的時候不會被呼叫

②bindView(View view, Context context, Cursor cursor)
bindView:從程式碼中可以看出在繪製Item之前一定會呼叫bindView方法它在重繪的時候也同樣被呼叫

4、更新ListView方法:adapter.changeCursor(cursor),它的功能類似於adapter.notifyDataSetChanged()方法

二、讀取通訊錄詳解

1、許可權

<!-- 讀取聯絡人許可權 -->
    <uses-permission android:name="android.permission.READ_CONTACTS"
>
</uses-permission> <!-- 撥打電話許可權 --> <uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>

2、獲取Cursor方法

Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,
                    PHONES_PROJECTION, null, null, null);

3、為什麼不使用Adapter繼承於BaseAdapter?
因為Object物件不能轉型為Cursor, 所以使用的Adapter繼承於CursorAdapter,才能轉型為CursorWrapper。


/**
     * 點選監聽實現
     * 
     * 實現:獲得選中項的電話號碼並撥號
     */
    private class onItemClickListener implements OnItemClickListener {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            //從指標的封裝類中獲得選中項的電話號碼並撥號
            //返回值是Object類需要向下轉型成CursorWrapper型別
            CursorWrapper wrapper = (CursorWrapper) lvContact.getItemAtPosition(position - 1);

            //返回從0開始的索引,如果列名不存在將返回-1
            int columnIndex = wrapper.getColumnIndex(Phone.NUMBER);

            if (!wrapper.isNull(columnIndex)) {
                String number = wrapper.getString(columnIndex);
                // 判斷電話號碼的有效性
                if (PhoneNumberUtils.isGlobalPhoneNumber(number)) {
                    Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel://" + number));
                    startActivity(intent);
                }
            }
        }
    }

三、例子程式碼

1、AndroidManifest.xml

 <!-- 讀取聯絡人許可權 -->
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <!-- 撥打電話許可權 -->
    <uses-permission android:name="android.permission.CALL_PHONE" />

2、item_contact.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:orientation="horizontal" >

        <ImageView
            android:id="@+id/iv_head"
            android:layout_width="45dp"
            android:layout_height="45dp"
            android:src="@mipmap/ic_launcher" />

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:gravity="center_vertical"
            android:layout_marginLeft="8dp"
            android:orientation="horizontal" >

            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical" >

                <TextView
                    android:id="@+id/name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="16sp"
                    android:text="TextView" />

                <TextView
                    android:id="@+id/number"
                    android:textSize="12sp"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="TextView" />
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

3、activity_contact.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/lv_contact"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">

    </ListView>
</RelativeLayout>

4、ContactAdapter.java

package com.guan.contentproviderwork.contact;

import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.v4.widget.CursorAdapter;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.guan.contentproviderwork.R;

import java.io.InputStream;
import java.util.ArrayList;

import butterknife.Bind;
import butterknife.ButterKnife;

/**
 * 定義介面卡
 * CursorAdapter為cursor和ListView提供了連線的橋樑
 *
 * @author Guan
 * @file com.guan.contentproviderwork
 * @date 2015/9/8
 * @Version 1.0
 */
public class ContactAdapter extends CursorAdapter {

    private Context mContext;

    /**
     * 聯絡人顯示名稱
     */
    private static final int PHONES_DISPLAY_NAME_INDEX = 1;

    /**
     * 電話號碼
     **/
    private static final int PHONES_NUMBER_INDEX = 2;

    /**
     * 頭像ID
     */
    private static final int PHONES_PHOTO_ID_INDEX = 3;

    /**
     * 聯絡人的ID
     */
    private static final int PHONES_CONTACT_ID_INDEX = 4;


    public ContactAdapter(Context context, Cursor cursor) {
        super(context,cursor);
        this.mContext = context;
    }

    @Override
    public int getCount() {

        if (mDataValid && mCursor != null) {
            return mCursor.getCount();
        } else {
            return 0;
        }
    }

    @Override
    public Object getItem(int position) {

        if (mDataValid && mCursor != null) {
            mCursor.moveToPosition(position);
            return mCursor;
        } else {
            return null;
        }
    }

    @Override
    public long getItemId(int position) {

        if (mDataValid && mCursor != null) {
            if ( mCursor.moveToPosition(position)) {
                return mCursor.getLong( mRowIDColumn);
            } else {
                return 0;
            }
        } else {
            return 0;
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View view;
        if (convertView == null) {
            view = newView(mContext, mCursor, parent);
        } else {
            view = convertView;
        }
        bindView(view, mContext, mCursor);
        return view;
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {

        ViewHolder viewholder = null;
        View view = LayoutInflater.from(mContext).inflate(
                R.layout.item_contact, null);
        viewholder = new ViewHolder(view);
        view.setTag(viewholder);
        return view;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {

        /**
         * 獲取當前position
         * final int position=cursor.getPosition();
         */

        ViewHolder viewholder = (ViewHolder) view.getTag();

        /**
         * 得到聯絡人名稱
         */
        viewholder.name.setText(cursor.getString(PHONES_DISPLAY_NAME_INDEX) + "");

        /**
         * 得到手機號碼
         */
        viewholder.number.setText(cursor.getString(PHONES_NUMBER_INDEX) + "");

        /**
         * 得到聯絡人頭像
         */
        // 得到聯絡人ID
        Long contactid = cursor
                .getLong(PHONES_CONTACT_ID_INDEX);
        // 得到聯絡人頭像ID
        Long photoid = cursor.getLong(PHONES_PHOTO_ID_INDEX);
        // 得到聯絡人頭像Bitamp
        Bitmap contactPhoto = null;
        // photoid 大於0 表示聯絡人有頭像 如果沒有給此人設定頭像則給他一個預設的
        if (photoid > 0) {
            Uri uri = ContentUris.withAppendedId(
                    ContactsContract.Contacts.CONTENT_URI,
                    contactid);
            InputStream input = ContactsContract.Contacts
                    .openContactPhotoInputStream(mContext.getContentResolver(), uri);
            contactPhoto = BitmapFactory.decodeStream(input);
        } else {
            contactPhoto = BitmapFactory.decodeResource(
                    mContext.getResources(), R.mipmap.ic_launcher);
        }

        viewholder.ivHead.setImageBitmap(contactPhoto);
    }


    /**
     * ViewHolder
     */
    static class ViewHolder {
        @Bind(R.id.iv_head)
        ImageView ivHead;
        @Bind(R.id.name)
        TextView name;
        @Bind(R.id.number)
        TextView number;

        ViewHolder(View view) {
            ButterKnife.bind(this, view);
        }
    }
}

5、ContactActivity.java

package com.guan.contentproviderwork.contact;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.telephony.PhoneNumberUtils;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

import com.guan.contentproviderwork.R;

import butterknife.Bind;
import butterknife.ButterKnife;

public class ContactActivity extends Activity {

    @Bind(R.id.lv_contact)
    ListView lvContact;

    /**
     * 聯絡人組
     */
    private static String[] PHONES_PROJECTION;

    /**
     * 聯絡人adapter
     */
    private ContactAdapter mContactAdapter;

    /**
     * Curosr
     */
    private Cursor mPhoneCursor;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_contact);
        ButterKnife.bind(this);

        // 初始化變數
        initValiable();
        // 獲取聯絡人Cursor
        getCursor();
        // 初始化listview
        bindData();
        // 初始化監聽
        initListener();
    }

    /**
     * 初始化變數
     */
    private void initValiable() {
        PHONES_PROJECTION = new String[]{
                "_id", Phone.DISPLAY_NAME, Phone.NUMBER, Phone.PHOTO_ID, Phone.CONTACT_ID};
    }

    /**
     * 獲取所有聯絡人Cursor
     */
    private Cursor getCursor() {
        ContentResolver resolver = getContentResolver();
        mPhoneCursor = resolver.query(Phone.CONTENT_URI,
                PHONES_PROJECTION, null, null, null);
        return mPhoneCursor;
    }

    /**
     * 繫結資料
     */
    private void bindData() {
        mContactAdapter = new ContactAdapter(ContactActivity.this, mPhoneCursor);
        lvContact.setAdapter(mContactAdapter);
    }

    /**
     * 初始化監聽
     */
    private void initListener() {
        lvContact.setOnItemClickListener(new onItemClickListener());
    }

    /**
     * 點選監聽實現
     * <p/>
     *
     * 實現:獲得選中項的電話號碼並撥號
     *
     * 注意:不能使用僅是繼承於BaseAdapter,因為Object物件不能轉型為Cursor。
     * 所以:使用的Adapter是繼承於CursorAdapter,才能轉型為CursorWrapper。
     */
    private class onItemClickListener implements OnItemClickListener {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            //從指標的封裝類中獲得選中項的電話號碼並撥號
            //返回值是Object類需要向下轉型成CursorWrapper型別
            CursorWrapper wrapper = (CursorWrapper) lvContact.getItemAtPosition(position - 1);

            //返回從0開始的索引,如果列名不存在將返回-1
            int columnIndex = wrapper.getColumnIndex(Phone.NUMBER);

            if (!wrapper.isNull(columnIndex)) {
                String number = wrapper.getString(columnIndex);
                // 判斷電話號碼的有效性
                if (PhoneNumberUtils.isGlobalPhoneNumber(number)) {
                    Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel://" + number));
                    startActivity(intent);
                }
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPhoneCursor.close();
    }

     /**
//     * 獲取所有聯絡人
//     */
//    private void getPhoneContacts() {
//
//        ContentResolver resolver = getContentResolver();
//        try {
//            // 獲取手機聯絡人
//            mPhoneCursor = resolver.query(Phone.CONTENT_URI,
//                    PHONES_PROJECTION, null, null, null);
//            if (mPhoneCursor != null) {
//
//                while (mPhoneCursor.moveToNext()) {
//
//                    // 得到手機號碼
//                    String phoneNumber = mPhoneCursor
//                            .getString(PHONES_NUMBER_INDEX);
//                    // 當手機號碼為空的或者為空欄位 跳過當前迴圈
//                    if (TextUtils.isEmpty(phoneNumber))
//                        continue;
//
//                    // 得到聯絡人名稱
//                    String contactName = mPhoneCursor
//                            .getString(PHONES_DISPLAY_NAME_INDEX);
//
//                    // 得到聯絡人ID
//                    Long contactid = mPhoneCursor
//                            .getLong(PHONES_CONTACT_ID_INDEX);
//
//                    // 得到聯絡人頭像ID
//                    Long photoid = mPhoneCursor.getLong(PHONES_PHOTO_ID_INDEX);
//
//                    // 得到聯絡人頭像Bitamp
//                    Bitmap contactPhoto = null;
//
//                    // photoid 大於0 表示聯絡人有頭像 如果沒有給此人設定頭像則給他一個預設的
//                    if (photoid > 0) {
//                        Uri uri = ContentUris.withAppendedId(
//                                ContactsContract.Contacts.CONTENT_URI,
//                                contactid);
//                        InputStream input = ContactsContract.Contacts
//                                .openContactPhotoInputStream(resolver, uri);
//                        contactPhoto = BitmapFactory.decodeStream(input);
//                    } else {
//                        contactPhoto = BitmapFactory.decodeResource(
//                                getResources(), R.mipmap.ic_launcher);
//                    }
//                    ContactEntity mContact = new ContactEntity(contactName,
//                            phoneNumber, contactPhoto);
//                    mContacts.add(mContact);
//                }
////                mPhoneCursor.close();
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }

}

四、效果圖

這裡寫圖片描述

五、推薦連結