安卓用QuickContactBadge和AsyncQueryHandler实现联系人列表的完美实现

本文主要是介绍安卓用QuickContactBadge和AsyncQueryHandler实现联系人列表的完美实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 在公司开发这么久了,发现好多的控件没有用过,然后发现了一些新的知识感觉还是很不错的,今天在这里我就来用一下QuickContactBadge的控件和AsyncQueryHandler,说到底QuickContactBadge这个控件我也是偶然发现的,然后乘着现在公司的工作不忙,然后也准备换工作温习一下知识点罢了。

一、介绍QuickContactBadge用法

    1、  先看一下它的结构

public class QuickContactBadge extends ImageView java.lang.Object 
implements View.OnClickListener
 ↳    android.view.View.imageView     
           ↳    android.widget.QuickContactBadge
      说到底QuickContactBadge就是我们经常用到的那个通讯录里面的那个头像,看过源码的都知道它是继承ImageView的并且是自带了点击事件的,所以我们用它的时候也就不用我们去自定义的布局,然后我们点击图像也会弹出一个popwindow来,然后里面就会有什么邮件,电话,短信的这些功能,效果还是可以的,功能很强大吧。

  2、看下QuickContactBadge的使用方法和介绍

(1)email调用
public void assignContactFromEmail (String emailAddress, boolean lazyLookup);
//指定联系人的电子邮箱地址。(注:它会先搜索这个号码,如果没有会提醒你是否添加到联系人
如果设置为true,将不//会立即查找这个邮箱地址,直到View被点击时。(注:是否延迟匹配电子邮件)
//参数 :  emailAddress:联系人的电子邮箱地址lazyLookup:
(2)电话的调用
public void assignContactFromPhone (String phoneNumber, boolean lazyLookup)//为联系人指定一个电话号码</span></div>//参数 
//phoneNumber : 联系人的电话号码
//lazyLookup  : 如果设置为true,将不会立即查找这个电话号码,直到View被点击时。
public void assignContactUri(Uri contactUri)
//这方法用得比较多,指定一个uri
 public void setMode(int size) ;//设计它的模式好像是3种(MODE_SMALL,MODE_MEDIUM,MODE_LARGE),这个是设计弹出dialog的大小
注意(优点):使用QuickContactBadge并不需要加入READ_CONTACTS权限。但是在无权限的情况下,如果联系人在通讯录里,则会直接进入查看联系人的界面,而不会有“拨打、查看、短信”三个选项。加入权限后则会出现

二、AsyncQueryHandler

因为QuickContactBadge是一个专门针对联系人所特制的控件,然后源码里也是使用AsyncQueryHandler来进行数据的操作,所以我们就来学习下
AsyncQueryHandler。

AsyncQueryHandler:异步的查询操作帮助类,其实它同样可以处理增删改

1。AsyncQueryHandler的作用

查询其API便可知,它担供:

startInsert,startDelete,startUpdate,startQuery

这四个操作,并提供相对应的onXXXComplete方法,以供操作完数据库后进行其它的操作,这四个onXXXComplete方法都是空实现,以便我们只需要去实现我们关注的操作。

2。为什么要使用AsyncQueryHandler

当然你也可以使用ContentProvider去操作数据库。这在数据量很小的时候是没有问题的,但是如果数据量大了,可能导致UI线程发生ANR事件。当然你也可以写个Handler去做这些操作,只是你每次使用ContentProvider时都要再写个Handler,必然降低了效率。

因此API提供了一个操作数据库的通用方法。

3。如何使用AsyncQueryHandler

你只需要继承AsyncQueryHandler类,并提供onXXXComplete方法的实现(可以实现任何一个或多个,当然你也可以一个也不实现,如果你不关注操作数据库的結果),在你的实现中做一些对数据库操作完成的处理。

使用时直接调用startXXX方法即可。传入的通用参数如下:

int token,一个令牌,需要跟onXXXComplete方法传入的一致。(当然你也可以不一致,同样在数据库的操作结束后会调用对应的onXXXComplete方法 )

Object cookie,你想传给onXXXComplete方法使用的一个对象。(没有的话传递null即可。基本发现这个变量没太大作用)

Uri uri,操作数据的URi

4。AsyncQueryHandler还为我们做了什么

AsyncQueryHandler中使用了一个WeakReference<ContentResolver>对象,即 ContentResolver的弱引用  作用:当contentProvied发生变化时候同步更新仍可以通过使用 AsyncQueryHandler类来达到这一要求(暂时还没理解这个作用)

同时,在它执行操作数据库时,吃掉了所有的异常。见如下代码。

 catch (Exception e) {
                        Log.w(TAG, e.toString());
                        cursor = null;
                    }

所以我们用他代替了contentProvider.

三、SparseArray的使用

SparseArray是 Android框架独有的类,在标准的JDK中不存在这个类。SparseArray实现了Cloneable接口,还可以调用clo

ne方法,它要比 HashMap 节省内存,某些情况下比HashMap性能更好,按照官方问答的解释,主要是因为SparseArray不需要

对key和value进行auto- boxing(将原始类型封装为对象类型,比如把int类型封装成Integer类型),结构比HashMap简单

(SparseArray内部主要使用 两个一维数组来保存数据,一个用来存key,一个用来存value)不需要额外的额外的数据结构(

主要是针对HashMap中的HashMapEntry 而言的)。

SparseArrays map integers to Objects.  Unlike a normal array of Objects,

* there can be gaps in the indices.  It is intended to be more memory efficient

* than using a HashMap to map Integers to Objects, both because it avoids object for each mapping.

* auto-boxing keys and its data structure doesn't rely on an extra entry

上面是谷歌对SparseArrays 的原话介绍,“It is intended to be more memory efficient than using a HashMap to map Integers to Object”虽然英语不是很好但是我想原意就是“的目的是要比使用一个HashMap整数映射到对象有效”,所以性能我就不测了反正用法和hashMap差不多但是性能好很多。
不多说下面直接上代码:
acitivity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/contact_list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"

        android:background="#E1E6F6" >
<ListView
android:id="@+id/contact_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:cacheColorHint="#7690A5"
        android:divider="#7690A5"
        android:fadingEdge="none"
        android:scrollbars="none"
        android:scrollingCache="false"
        android:visibility="visible" />
<com.zy.quilkycontact.AlphabeticBarandroid:id="@+id/fast_scroller"
        android:layout_width="22dp"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:layout_gravity="top|right|center"
        android:layout_marginTop="0dip"
        android:background="@null"
        android:scaleType="centerInside"
        android:src="@drawable/dic_background" >
</com.zy.quilkycontact.AlphabeticBar>
<TextView
android:id="@+id/fast_position"
        android:layout_width="70dip"
        android:layout_height="70dip"
        android:layout_centerInParent="true"
        android:layout_gravity="center_horizontal|top"
        android:layout_margin="34dip"
        android:background="@drawable/flag"
        android:gravity="center"
        android:padding="2dip"
        android:textColor="#404040"
        android:textSize="48dip"
        android:visibility="invisible" />
</RelativeLayout>
然后是item的布局:contact_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
<!-- 首字母 -->
<TextView
android:id="@+id/alpha"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#7690A5"
        android:paddingLeft="10dip"
        android:textColor="#FFFFFF"
        android:visibility="gone" />
<!-- 联系人信息 -->
<QuickContactBadge
android:id="@+id/contact"
        android:layout_width="75dip"
        android:layout_height="75dip"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/alpha"
        android:layout_marginBottom="3dip"
        android:layout_marginTop="3dip"
        android:src="@drawable/login_icon_member"
        style="?android:attr/quickContactBadgeStyleWindowSmall"  />
<TextView
android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/contact"
        android:singleLine="true"
        android:layout_marginLeft="50dp"
        android:textAppearance="?android:textAppearanceLarge"
        android:textColor="#FFFFFF" />
<TextView
android:id="@+id/number"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_toRightOf="@+id/contact"
        android:singleLine="true"
        android:layout_marginLeft="50dp"
        android:textAppearance="?android:textAppearanceSmall"
        android:textColor="#FFFFFF" />
</RelativeLayout>
接下来是代码的编写:
1.先准备一个实体bean:联系人的实体类Contact.java
package com.zy.quilkycontact;
public class Contact {private int contactId; //id
    private String desplayName;//姓名
    private String phoneNum; // 电话号码
    private String sortKey; // 排序用的
    private Long photoId; // 图片id
    private String lookUpKey;
    private int selected = 0;
    private String formattedNumber;
    private String pinyin; // 姓名拼音
    private String email;
    public int getContactId() {return contactId;
    }public void setContactId(int contactId) {this.contactId = contactId;
    }public String getDesplayName() {return desplayName;
    }public void setDesplayName(String desplayName) {this.desplayName = desplayName;
    }public String getPhoneNum() {return phoneNum;
    }public void setPhoneNum(String phoneNum) {this.phoneNum = phoneNum;
    }public String getSortKey() {return sortKey;
    }public void setSortKey(String sortKey) {this.sortKey = sortKey;
    }public Long getPhotoId() {return photoId;
    }public void setPhotoId(Long photoId) {this.photoId = photoId;
    }public String getLookUpKey() {return lookUpKey;
    }public void setLookUpKey(String lookUpKey) {this.lookUpKey = lookUpKey;
    }public int getSelected() {return selected;
    }public void setSelected(int selected) {this.selected = selected;
    }public String getFormattedNumber() {return formattedNumber;
    }public void setFormattedNumber(String formattedNumber) {this.formattedNumber = formattedNumber;
    }public String getPinyin() {return pinyin;
    }public void setPinyin(String pinyin) {this.pinyin = pinyin;
    }public String getEmail() {return email;
    }public void setEmail(String email) {this.email = email;
    }
2.仿通讯录的带拼音的字母滑块控件AlphabeticBar.java
package com.zy.quilkycontact;
        import java.util.HashMap;
        import android.app.Activity;
        import android.content.Context;
        import android.graphics.Canvas;
        import android.graphics.Color;
        import android.graphics.Paint;
        import android.graphics.Typeface;
        import android.os.Handler;
        import android.util.AttributeSet;
        import android.view.MotionEvent;
        import android.view.View;
        import android.widget.ImageButton;
        import android.widget.ListView;
        import android.widget.TextView;
/**
 * 字母索引条
 *
 *
 */
public class AlphabeticBar extends ImageButton {private TextView mDialogText; // 中间显示字母的文本框
    private Handler mHandler; // 处理UI的句柄
    private ListView mList; // 列表
    private float mHight; // 高度
    // 字母列表索引
    private String[] letters = new String[] { "#", "A", "B", "C", "D", "E",
            "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z" };
    // 字母索引哈希表
    private HashMap<String, Integer> alphaIndexer;
    Paint paint = new Paint();
    boolean showBkg = false;
    int choose = -1;


    public AlphabeticBar(Context context) {this(context, null);
    }public AlphabeticBar(Context context, AttributeSet attrs) {this(context, attrs, 0);
    }public AlphabeticBar(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);
    }// 初始化
    public void init(Activity ctx) {mDialogText = (TextView) ctx.findViewById(R.id.fast_position);
        mDialogText.setVisibility(View.INVISIBLE);
        mHandler = new Handler();
    }// 设置需要索引的列表
    public void setListView(ListView mList) {this.mList = mList;
    }// 设置字母索引哈希表
    public void setAlphaIndexer(HashMap<String, Integer> alphaIndexer) {this.alphaIndexer = alphaIndexer;
    }// 设置字母索引条的高度
    public void setHight(float mHight) {this.mHight = mHight;
    }@Overridepublic boolean onTouchEvent(MotionEvent event) {int act = event.getAction();
        float y = event.getY();
        final int oldChoose = choose;
// 计算手指位置,找到对应的段,让mList移动段开头的位置上
        int selectIndex = (int) (y / (mHight / letters.length));
        if (selectIndex > -1 && selectIndex < letters.length) { // 防止越界
            String key = letters[selectIndex];
            if (alphaIndexer.containsKey(key)) {int pos = alphaIndexer.get(key);
                if (mList.getHeaderViewsCount() > 0) { // 防止ListView有标题栏,本例中没有
                    this.mList.setSelectionFromTop(pos + mList.getHeaderViewsCount(), 0);
                } else {this.mList.setSelectionFromTop(pos, 0);
                }}}switch (act) {case MotionEvent.ACTION_DOWN:
                showBkg = true;
                if (oldChoose != selectIndex) {if (selectIndex > 0 && selectIndex < letters.length) {choose = selectIndex;
                        invalidate();
                    }}break;
            case MotionEvent.ACTION_MOVE:
                if (oldChoose != selectIndex) {if (selectIndex > 0 && selectIndex < letters.length) {choose = selectIndex;
                        invalidate();
                    }}break;
            case MotionEvent.ACTION_UP:
                showBkg = false;// 不显示
                choose = -1;
                break;
            default:
                break;
        }return super.onTouchEvent(event);
    }@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);
        int height = getHeight();
        int width = getWidth();
        int sigleHeight = height / letters.length; // 单个字母占的高度
        for (int i = 0; i < letters.length; i++) {paint.setColor(Color.WHITE);
            paint.setTextSize(20);
            paint.setTypeface(Typeface.DEFAULT_BOLD);
            paint.setAntiAlias(true);
            if (i == choose) {paint.setColor(Color.parseColor("#00BFFF")); // 滑动时按下字母颜色
                paint.setFakeBoldText(true);
//选中后先显示选中的字目
                mHandler.post(new Runnable() {@Overridepublic void run() {if (mDialogText != null) {mDialogText.setVisibility(VISIBLE);
                            mDialogText.setText(letters[choose]);// 设置选中的滑动字母
                        }}});
//o.3秒后隐藏
                mHandler.postDelayed(new Runnable() {@Overridepublic void run() {mDialogText.setVisibility(INVISIBLE);
                    }}, 300);

            }
// 绘画的位置
            float xPos = width / 2 - paint.measureText(letters[i]) / 2;
            float yPos = sigleHeight * i + sigleHeight;
            canvas.drawText(letters[i], xPos, yPos, paint);
            paint.reset();
        }}}

  
MainActivity.java
package com.zy.quilkycontact;
        import java.util.HashMap;
        import java.util.Map;
        import android.annotation.SuppressLint;
        import android.app.Activity;
        import android.content.AsyncQueryHandler;
        import android.content.ContentResolver;
        import android.database.Cursor;
        import android.net.Uri;
        import android.os.Bundle;
        import android.provider.ContactsContract;
        import android.util.SparseArray;
        import android.view.View;
        import android.view.Window;
        import android.widget.ListView;


/**
 * 联系人列表
 *
 *
 */
public class MainActivity extends Activity {private ContactListAdapter adapter;
    private ListView contactListView;
    private SparseArray<Contact> list;
    private AsyncQueryHandler asyncQueryHandler; // 异步查询数据库类对象
    private AlphabeticBar alphabeticBar; // 快速索引条
    private Map<Integer, Contact> contactIdMap = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        contactListView = (ListView) findViewById(R.id.contact_list);
        alphabeticBar = (AlphabeticBar) findViewById(R.id.fast_scroller);
// 实例化
        asyncQueryHandler = new MyAsyncQueryHandler(getContentResolver());
        initDatas();


    }/**
     * 初始化数据库查询参数
     */
    private void initDatas() {Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI; // 联系人Uri;
// 查询的字段
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID,
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.DATA1, "sort_key",
                ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
                ContactsContract.CommonDataKinds.Phone.PHOTO_ID,
                ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY };
// 按照sort_key升序查詢
        asyncQueryHandler.startQuery(0, null, uri, projection, null, null,
                "sort_key COLLATE LOCALIZED asc");


    }/**
     * 使用异步方式对DB数据库进行基本的增,删,改,查
     * */
    private class MyAsyncQueryHandler extends AsyncQueryHandler {public MyAsyncQueryHandler(ContentResolver cr) {super(cr);
        }@SuppressLint("UseSparseArrays")protected void onQueryComplete(int token, Object cookie, Cursor cursor) {if (cursor != null && cursor.getCount() > 0) {contactIdMap = new HashMap<Integer, Contact>();
                list = new SparseArray<Contact>();
                cursor.moveToFirst(); // 游标移动到第一项
                for (int i = 0; i < cursor.getCount(); i++) {cursor.moveToPosition(i);
                    String name = cursor.getString(1);
                    String number = cursor.getString(2);
                    String sortKey = cursor.getString(3);//首字母
                    int contactId = cursor.getInt(4);
                    Long photoId = cursor.getLong(5);
                    String lookUpKey = cursor.getString(6);
                    String email = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
                    if (contactIdMap.containsKey(contactId)) {
// 无操作
                    } else {
// 创建联系人对象
                        Contact contact = new Contact();
                        contact.setDesplayName(name);
                        contact.setPhoneNum(number);
                        contact.setSortKey(sortKey);
                        contact.setPhotoId(photoId);
                        contact.setLookUpKey(lookUpKey);
                        contact.setEmail(email);
                        list.put(i, contact);
                        contactIdMap.put(contactId, contact);
                    }}if (list.size() > 0) {setAdapter(list);
                }}super.onQueryComplete(token, cookie, cursor);
        }}private void setAdapter(SparseArray<Contact> list) {adapter = new ContactListAdapter(this, list, alphabeticBar);
        contactListView.setAdapter(adapter);
        alphabeticBar.init(MainActivity.this);
        alphabeticBar.setListView(contactListView);
        alphabeticBar.setHight(alphabeticBar.getHeight());
        alphabeticBar.setVisibility(View.VISIBLE);
    }
}
好了所有的代码都写完了然后我们的清单文件可别忘记配置了
<!-- 读联系人权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- 写联系人权限 -->
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<!-- 拨号权限 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!-- 读短信权限 -->
<uses-permission android:name="android.permission.READ_SMS" />

好了,所有的代码也是写完了,我们看下运行效果
这就是效果,功能还是比较渣渣,那个QuickContactBadge的图像你可以换张好看点的图片,那个弹出的dialog里面3个图标是可以点击的,点了后回去对应的程序里面运行,图不太好截,所以就不给了。
要下源码:请戳》》》下载地址(0积分)

这篇关于安卓用QuickContactBadge和AsyncQueryHandler实现联系人列表的完美实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131773

相关文章

windos server2022里的DFS配置的实现

《windosserver2022里的DFS配置的实现》DFS是WindowsServer操作系统提供的一种功能,用于在多台服务器上集中管理共享文件夹和文件的分布式存储解决方案,本文就来介绍一下wi... 目录什么是DFS?优势:应用场景:DFS配置步骤什么是DFS?DFS指的是分布式文件系统(Distr

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

Python xmltodict实现简化XML数据处理

《Pythonxmltodict实现简化XML数据处理》Python社区为提供了xmltodict库,它专为简化XML与Python数据结构的转换而设计,本文主要来为大家介绍一下如何使用xmltod... 目录一、引言二、XMLtodict介绍设计理念适用场景三、功能参数与属性1、parse函数2、unpa

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如