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

本文主要是介绍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_URICONTENT_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_SMALLMODE_MEDIUMMODE_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.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

这个控件也是一个自定义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


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



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

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给