QuickContactBadge和AsyncQueryHandler实现联系人列表完美实现

打造你自己的个性联系人列表

我也是醉了,昨天下午写的博客有点小问题把已经发布的博客修改了下,然后今天博客就丢失了(猛然发现点击打开链接被转载到那里去了,算了还是出现整理下吧,那里好像有的地方说的不明白有错误),最近呢也是准备换工作,还是要把一些知识点呢重新回顾下,本博客呢是介绍用QuickContactBadge和AsyncQueryHandler实现联系人列表完美实现,说实在的这些东西在项目里不一定用得上,但是越是让我们忽略的东西或许会让我们觉得更加的学习价值,有可能让我们从公司的项目外学到一些意外的东西。每个知识点都有可能存在他的意义。

一、QuickContactBadge的介绍

说实在的当我们不了解这个控件的时候,或许我们还在自定义这个东西,然后在谷歌的官网里就有这么个专门封装好的控件顿时觉得我们是多么的逗比,仔细去看下这控件的源码,不得不说确实里面还进行了系统的优化,好过我们还傻不拉几的用什么ContentResolver自己去慢慢查,性能明显就还是跟不上了,现在好了我们可以放心大胆的用了,还节省了很多的代码,性能也跟得上去这不是程序员梦寐以求的吗,说到底QuickContactBadge就是我们经常用到的那个通讯录里面的那个头像,看过源码的都知道它是继承ImageView的并且是自带了点击事件的,所以我们用它的时候也就不用我们去自定义的布局,然后我们点击图像也会弹出一个popwindow来,然后里面就会有什么邮件,电话,短信的这些功能,效果还是可以的,功能很强大吧。QuickContacBadge译为联系人快捷标识,用于显示一张图片,点击该图后弹出相关的快捷功能,轻松实现打电话、发短信、email的功能等。。

QuickContactBadge继承了ImageView,因此它的本质也是图片,也可以通过android:src属性指定它显示的图片。QuickContackBadge额外功能是:该图片可以关联到手机中指定联系人,当用户单击该图片时,系统将打开相应的联系人的联系方式界面。

一、结构

    java.lang.Object

     android.view.View

     android.widget.ImageView

     android.widget.QuickContactBadge

可以调用如下方法进行关联:

public void assignContactFromEmail (String emailAddress, boolean lazyLookup)

指定联系人的电子邮箱地址。(注:它会先搜索这个号码,如果没有会提醒你是否添加到联系人)

    参数 emailAddress          联系人的电子邮箱地址

      lazyLookup      如果设置为true,将不会立即查找这个邮箱地址,直到View被点击时。(注:是否延迟匹配电子邮件)

public void assignContactFromPhone (String phoneNumber, boolean lazyLookup)

为联系人指定一个电话号码。

      参数     phoneNumber  联系人的电话号码            lazyLookup     如果设置为true,将不会立即查找这个电话号码,直到View被点击时。

public void assignContactUri (Uri contactUri)

指定和QuickContactBadge关联的联系人URI。注意,这里只是显示QuickContact窗口,并不为你绑定联系人图片。

参数     contactUri       CONTENT_URI或CONTENT_LOOKUP_URI其中一种风格的URI.

public void onClick (View v)//  当View被点击时调用。  参数 v
     被点击的View.

public void setExcludeMimes (String[] excludeMimes)

设置一组要排除不显示的MIMI类型列表。例如,可以隐藏Contacts.CONTENT_ITEM_TYPE类型的图标。(注:如果像如下设置:

  setExcludeMimes(new String[] { Contacts.CONTENT_ITEM_TYPE })

  即隐藏了上面截图的第二个,仅显示电话和短信两个图标)

public void setMode (int size)////设计它的模式好像是3种(MODE_SMALL,MODE_MEDIUM,MODE_LARGE),这个是设计弹出dialog的大小

设置QuickContact的窗口模式。如下选项:MODE_SMALL、MODE_MEDIUM、MODE_LARGE。(注:默认为QuickContact.MODE_MEDIUM,设置为MODE_LARGE时会同时显示联系人名称)

注意(优点):使用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的使用

本来写代码的时候用的是HashMap,实例化时,Eclipse却给出了一个 performance 警告。

然后就不由自主的按住ctrl键,结果发现了一段话,让我又学到了一个知识点

* 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

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

* for each mapping.

上面一段是源码的注释《《It is intended to be more memory efficient than using a HashMap
to map Integers to Objects》》,虽然英语不是很好,但是我知道这句话大意是:这个类在映射整数对象时比hashMap的效率更好!!!!接下来我们就来看SparseArray:

SparseArray是
Android框架独有的类,在标准的JDK中不存在这个类。SparseArray实现了Cloneable接口,还可以调用clone方法,它要比 HashMap 节省内存,某些情况下比HashMap性能更好,按照官方问答的解释,主要是因为SparseArray不需要对key和value进行auto- boxing(将原始类型封装为对象类型,比如把int类型封装成Integer类型),结构比HashMap简单(SparseArray内部主要使用 两个一维数组来保存数据,一个用来存key,一个用来存value)不需要额外的额外的数据结构(主要是针对HashMap中的HashMapEntry
而言的)。

SparseArray就是稀疏数组(参见  http://hi.baidu.com/piaopiao_0423/item/d8cc2b99729f8380581461d1)。《此处参考考http://blog.csdn.net/easyer2012/article/details/37871031》》》

 所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以采用一种压缩的方式来表示稀疏数组的内容。

  假设有一个9*7的数组,其内容如下:

       图 1 二维数组示例

  在此数组中,共有63个空间,但却只使用了5个元素,造成58个元素空间的浪费。以下我们就使用稀疏数组重新来定义这个数组:

      图 2 使用稀疏数组进行压缩

其中在稀疏数组中第一部分所记录的是原数组的列数和行数以及元素使用的个数、第二部分所记录的是原数组中元素的位置和内容。经过压缩之后,原来需要声明大小为63的数组,而使用压缩后,只需要声明大小为6*3的数组,仅需18个存储空间。

然后对我们对SparseArray的用法就不做介绍了,和hashMap的差不多。

总结:SparseArray是android里为<Interger,Object>这样的Hashmap而专门写的类,目的是提高内存效率,其核心是折半查找函数(binarySearch)。注意内存二字很重要,因为它仅仅提高内存效率,而不是提高执行效率,所以也决定它只适用于android系统(内存对android项目有多重要,地球人都知道)。SparseArray有两个优点:1.避免了自动装箱(auto-boxing),2.数据结构不会依赖于外部对象映射。我们知道HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置,存放的都是数组元素的引用,通过每个对象的hash值来映射对象。而SparseArray则是用数组数据结构来保存映射,然后通过折半查找来找到对象。但其实一般来说,SparseArray执行效率比HashMap要慢一点,因为查找需要折半查找,而添加删除则需要在数组中执行,而HashMap都是通过外部映射。但相对来说影响不大,最主要是SparseArray不需要开辟内存空间来额外存储外部映射,从而节省内存。

到此我们就直接上代码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.AlphabeticBar

android: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

这个控件也是一个自定义veiw的小实现吧,不多说搞安卓有经验的多少有些了解,直接上代码,里面的代码还是写的不怎么样,没有办法凑合着用吧。

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;

}

@Override

public 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);

}

@Override

protected 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() {

@Override

public void run() {

if (mDialogText != null) {

mDialogText.setVisibility(VISIBLE);

mDialogText.setText(letters[choose]);// 设置选中的滑动字母

}

}

});

//o.3秒后隐藏

mHandler.postDelayed(new Runnable() {

@Override

public 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();

}

}

}

3.接下来我们就写联系人的适配器ContactListAdapter.java

package com.zy.quilkycontact;

import java.io.InputStream;

import java.util.ArrayList;

import java.util.Collections;

import java.util.HashMap;

import java.util.List;

import java.util.Set;

import java.util.regex.Pattern;

import android.content.ContentUris;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.net.Uri;

import android.provider.ContactsContract;

import android.provider.ContactsContract.Contacts;

import android.provider.ContactsContract.QuickContact;

import android.util.SparseArray;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.QuickContactBadge;

import android.widget.TextView;

public class ContactListAdapter extends BaseAdapter {

private LayoutInflater inflater;

private SparseArray<Contact> list;

private HashMap<String, Integer> alphaIndexer; // 字母索引

private String[] sections; // 存储每个章节

private Context ctx; // 上下文

public ContactListAdapter(Context context, SparseArray<Contact> list,

AlphabeticBar alpha) {

this.ctx = context;

this.inflater = LayoutInflater.from(context);

this.list = list;

this.alphaIndexer = new HashMap<String, Integer>();

this.sections = new String[list.size()];

int count=list.size();

for (int i = 0; i <count; i++) {

// 得到字母字符串的首字母

String name = getAlpha(list.get(i).getSortKey());

if (!alphaIndexer.containsKey(name)) {

alphaIndexer.put(name, i);

}

}

Set<String> sectionLetters = alphaIndexer.keySet();//获取所有的key值

ArrayList<String> sectionList = new ArrayList<String>(sectionLetters);

Collections.sort(sectionList); // 根据首字母进行排序

sections = new String[sectionList.size()];

sectionList.toArray(sections);//转化为数组

alpha.setAlphaIndexer(alphaIndexer);

}

@Override

public int getCount() {

return list.size();

}

@Override

public Object getItem(int position) {

return list.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

public void remove(int position) {

list.remove(position);

}

@Override

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

ViewHolder holder;

if (convertView == null) {

convertView = inflater.inflate(R.layout.contact_list_item, parent,false);

holder = new ViewHolder();

holder.quickContactBadge = (QuickContactBadge) convertView

.findViewById(R.id.contact);

holder.alpha = (TextView) convertView.findViewById(R.id.alpha);

holder.name = (TextView) convertView.findViewById(R.id.name);

holder.number = (TextView) convertView.findViewById(R.id.number);

convertView.setTag(holder);

} else {

holder = (ViewHolder) convertView.getTag();

}

Contact contact = list.get(position);

String name = contact.getDesplayName();

String number = contact.getPhoneNum();

holder.name.setText(name);

holder.number.setText(number);

holder.quickContactBadge.assignContactUri(Contacts.getLookupUri(

contact.getContactId(), contact.getLookUpKey()));

//holder.quickContactBadge.assignContactFromEmail(contact.getEmail(),false);//关联emali

holder.quickContactBadge.setMode(ContactsContract.QuickContact.MODE_SMALL);

if (0 == contact.getPhotoId()) {

holder.quickContactBadge.setImageResource(R.drawable.login_icon_member);

} else {

Uri uri = ContentUris.withAppendedId(

ContactsContract.Contacts.CONTENT_URI,

contact.getContactId());

InputStream input = ContactsContract.Contacts

.openContactPhotoInputStream(ctx.getContentResolver(), uri);

Bitmap contactPhoto = BitmapFactory.decodeStream(input);

holder.quickContactBadge.setImageBitmap(contactPhoto);

}

// 当前显示的首字母

String currentStr = getAlpha(contact.getSortKey());

// 前面的字母

String previewStr = (position - 1) >= 0 ? getAlpha(list.get(

position - 1).getSortKey()) : " ";

if (!previewStr.equals(currentStr)) {//如果当前显示的首字母和以前的首字母不同

holder.alpha.setVisibility(View.VISIBLE);//显示

holder.alpha.setText(currentStr);

} else {//相同时顶部栏不显示

holder.alpha.setVisibility(View.GONE);

}

return convertView;

}

private static class ViewHolder {

QuickContactBadge quickContactBadge;

TextView alpha;

TextView name;

TextView number;

}

/**

* 获取首字母

*

* @param str

* @return

*/

private String getAlpha(String str) {

if (str == null) {//字母不存在返回为#号

return "#";

}

if (str.trim().length() == 0) {

return "#";

}

char c = str.trim().substring(0, 1).charAt(0);//获取首字母

// 正则表达式匹配(从a到z的字母)

Pattern pattern = Pattern.compile("^[A-Za-z]+$");

if (pattern.matcher(c + "").matches()) {//如果首字母是a-z里面的任一字母

return (c + "").toUpperCase(); // 将小写字母转换为大写

} else {

return "#";

}

}

}

4.最后我们就可以书写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" />

下面我们来看下效果,(我也是醉了,http://www.it165.net/pro/html/201504/39496.html把我的转过去,直接还附带了他们的下载地址,就连图片包名都不改,没有办法懒得运行了把那原图考过来了咯)

这就是效果,功能还是比较渣渣,那个QuickContactBadge的图像你可以换张好看点的图片,那个弹出的dialog里面3个图标是可以点击的,点了后回去对应的程序里面运行,图不太好截,所以就不给了。

下源码:(醉了)http://download.csdn.net/detail/u013278099/8641529

时间: 2024-08-27 20:20:05

QuickContactBadge和AsyncQueryHandler实现联系人列表完美实现的相关文章

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

打造你自己的个性联系人列表 在公司开发这么久了,发现好多的控件没有用过,然后发现了一些新的知识感觉还是很不错的,今天在这里我就来用一下QuickContactBadge的控件和AsyncQueryHandler,说到底QuickContactBadge这个控件我也是偶然发现的,然后乘着现在公司的工作不忙,然后也准备换工作温习一下知识点罢了. 一.介绍QuickContactBadge用法 1.  先看一下它的结构 <div style="text-align: justify;"

Android带索引联系人列表

网上Android联系人列表的样例也非常多,都和微信的联系人差点儿相同,因为项目用到了联系人列表索引功能(产品把字母item给去掉了),只是也还是好实现.这里我也来分享分享我的实现,免得以后忘了.那先看看效果(Demo在结尾有下载地址): 要达到的效果就是这么简单. 先说说思路吧:首先为联系人对象加入一个pinyin字段,当获取到了联系人原始数据后,把每一个联系人的名字转换为拼音.并为pinyin字段设置值. 然后获取联系人中出现过哪些字母的拼音保存为数组(这就是字母的item),然后和联系人拼

带中文索引的ListView 仿微信联系人列表

由于各种原因,项目经理和产品经理把我做的东西给否定了,所以决定分享出去. 主要功能: 1 .带中文索引的ListView 2.自定义顶部搜索视图,可以对返回按钮,搜索按钮添加事件监听,带动画的咧!~ 3.底部自定义视图,可以对Listview的adapter添加监听,并且回调选中的数目,另外其他的视图都是可以自己添加的 4.右侧的索引视图,根据通讯录的解析后的数据动态生成相关索引列表 5.Adapter的抽象类,想优化自己的Adapter可以看一下,例子中的adapter仅仅是特例特写. 6.分

Android UI(五)云通讯录项目之联系人列表,带侧滑选择,带搜索框

作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节.交流QQ群:[编程之美 365234583]http://jq.qq.com/?_wv=1027&k=XVfBTo 要捐钱的就打支付宝吧:13958686678(泥瓦匠开个玩笑~) 一.前言 继续AndroidUI系列,泥瓦匠又要开始扯淡了.哈哈今天在文章头加了个支付宝账号.我也真逗,至今没收到一笔是写博客的钱.或是分享的.泥瓦匠也就挂着逗逗乐

Android仿联系人列表分组悬浮列表,PinnedHeaderListView源码解析

github地址:https://github.com/JimiSmith/PinnedHeaderListView 关于实现类似联系人列表,组的头部总是悬浮在listview最顶部的效果,github上面有两个比较好的实现,分别是pinnedSectionListview和pinnedHeaderListView,之所以选择后者进行源码解析,是因为后者的源码比较简单,便于我们理解实现的精髓所在. 如果你想直接实现Android仿联系人列表分组悬浮列表, 自定义PinnedHeaderListV

iOS项目-联系人列表

一,项目介绍 首先,简单介绍一下这个项目的效果 进入程序,首先是登录页面 登录页面用到 NSUserDefault 记住登录密码 然后是 然后是登录跳转,用到MBProgressHUD 接着是联系人列表 是一个UITableView 点击+ 进入添加联系人页面 点击每行联系人 进入编辑界面 点击注销,弹出UIAlertController 二,进入代码 首先 在SB中构建视图的架构 然后建立几个对应的控制器,并做好子类链接 然后实现 登录界面 首先添加观察者,监视textfield的值的变化 [

动手分析安卓仿QQ联系人列表TreeView控件

因项目需要需要用到仿QQ联系人列表的控件样式,于是网上找到一个轮子(https://github.com/TealerProg/TreeView),工作完成现在简单分析一下这个源码.   一. 需要用到的知识如下: ①安卓事件分发机制:(http://blog.csdn.net/lvxiangan/article/details/9309927  或 http://gundumw100.iteye.com/blog/1052270) ②安卓View绘制:http://blog.csdn.net/

获取手机的联系人列表和打电话

获取手机中的联系人列表,需要用到系统给我们提供的框架:AddressBook.framework, 1.导入框架; 2.简历模型和管理者: 模型: .h #import <Foundation/Foundation.h> @interface Contact : NSObject @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *phone; +(instancetype)

如何在泰国#组联系人列表中的联系人姓名分类?

联系人姓名开头的数字被放置在"#"默认情况下.如果你想显示联系人的姓名在泰国在底部并创建一个新的"#"组,修改如下: 在接触到的名字显示在"#泰集团,包括接触的名字开始与"0-9,修改\ufff到\u0039. 如果是JB 1. 在 ContactsDatabaseHelper.java (packages\providers\contactsprovider\src\com\android\providers\contacts) 函数 upda