注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。

原文链接:http://developer.android.com/training/contacts-provider/display-contact-badge.html


这节课将会向你展示如何添加一个QuickContactBadge到你的UI中,以及如何将数据和它捆绑起来。一个QuickContactBadge是一个显示缩略图的空间。虽然你可以使用Bitmap显示任何缩略图,但是你必须要将联系人照片进行解码。

缩略图的作用类似于一个控制器:当用户点击缩略图时,QuickContactBadge会扩展成一个对话框,其中包含如下内容:

一个放大的图标

一个和该联系人关联的大图标,如果没有的话,就用一个默认的占位图片代替。

应用图标

每一个具体的联系人信息旁会有一个应用图标,它说明该数据可被此内置应用处理。例如,如果联系人的数据中有一个或多个email地址,那么就会出现一个email的图标。当用户点击这个图标,联系人的所有email地址会显示出来,之后用户如果点击了某一个email地址,会打开电子邮件应用,其中的收件人地址就是所选中的email地址。

QuickContactBadge提供了一个指向联系人详细信息的即时访问,以及一个和联系人沟通的快速渠道。用户不需要查询联系人列表,寻找并拷贝信息,之后再把它粘贴到其它的应用界面中去。取而代之的,它们只需要在QuickContactBadge上进行点击,选择他们想要使用的沟通方式,并直接通过相关的应用发送消息即可。


一). 添加一个QuickContactBadge视图

要添加一个QuickContactBadge,在你的布局中插入一个<QuickContactBadge>元素,例如:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"                android:layout_width="match_parent"                android:layout_height="match_parent">...    <QuickContactBadge               android:id=@+id/quickbadge               android:layout_height="wrap_content"               android:layout_width="wrap_content"               android:scaleType="centerCrop"/>    ...</RelativeLayout>

二). 检索提供器的数据

要在QuickContactBadge中显示一个联系人,你需要一个联系人的内容URI还有缩略图的Bitmap对象。你从Contacts Provider搜索的列数据用来创建内容URI和Bitmap对象。指定这些列左右你在Cursor中用来加载数据的投影的一部分。

对Android 3.0(API版本11)及之后的版本,在你的投影中包含下面几列:

  • Contacts._ID
  • Contacts.LOOKUP_KEY
  • Contacts.PHOTO_THUMBNAIL_URI

对Android 2.3.3(API版本10)及之前的版本,在你的投影中包含下面几列:

  • Contacts._ID
  • Contacts.LOOKUP_KEY

我们假设在这节课之前,你已经加载了一个Cursor,它包含了上面的这些列,还有一些你已经选择了的列。要学习如何使用Cursor检索这些列数据,可以参阅:Retrieving a List of Contacts(博客链接:http://www.cnblogs.com/jdneo/p/3674830.html)


三). 设置内容URI和缩略图

一旦你有了必要的列,你就可以将数据绑定到QuickContactBadge上。

设置内容URI

要为联系人的内容URI,调用getLookupUri(id,lookupKey)来获取一个CONTENT_LOOKUP_URI,然后调用assignContactUri()来设置联系人。例如:

    // The Cursor that contains contact rows    Cursor mCursor;    // The index of the _ID column in the Cursor    int mIdColumn;    // The index of the LOOKUP_KEY column in the Cursor    int mLookupKeyColumn;    // A content URI for the desired contact    Uri mContactUri;    // A handle to the QuickContactBadge view    QuickContactBadge mBadge;    ...    mBadge = (QuickContactBadge) findViewById(R.id.quickbadge);    /*     * Insert code here to move to the desired cursor row     */    // Gets the _ID column index    mIdColumn = mCursor.getColumnIndex(Contacts._ID);    // Gets the LOOKUP_KEY index    mLookupKeyColumn = mCursor.getColumnIndex(Contacts.LOOKUP_KEY);    // Gets a content URI for the contact    mContactUri =            Contacts.getLookupUri(                mCursor.getLong(mIdColumn),                mCursor.getString(mLookupKeyColumn)            );    mBadge.assignContactUri(mContactUri);

当用户点击了QuickContactBadge图标后,联系人的详细信息会自动显示在对话框中。

设置照片缩略图

为QuickContactBadge设置联系人的URI并不会自动的加载他的照片。要加载照片,需要从联系人的Cursor行中获取照片的URI,使用它来打开包含有压缩后的照片缩略图文件,并将该文件读入一个Bitmap对象。

Note:

PHOTO_THUMBNAIL_URI列在Android 3.0之前的版本中是没有的。对于那些较早的版本,你必须从Contacts.Photo自表中获取URI。

首先,为访问包含有Contacts._ID和Contacts.LOOKUP_KEY列的Cursor设置变量,如下所示:

    // The column in which to find the thumbnail ID    int mThumbnailColumn;    /*     * The thumbnail URI, expressed as a String.     * Contacts Provider stores URIs as String values.     */    String mThumbnailUri;    ...    /*     * Gets the photo thumbnail column index if     * platform version >= Honeycomb     */    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {        mThumbnailColumn =                mCursor.getColumnIndex(Contacts.PHOTO_THUMBNAIL_URI);    // Otherwise, sets the thumbnail column to the _ID column    } else {        mThumbnailColumn = mIdColumn;    }    /*     * Assuming the current Cursor position is the contact you want,     * gets the thumbnail ID     */    mThumbnailUri = mCursor.getString(mThumbnailColumn);    ...

定义一个方法,它获取联系人的照片数据,以及缩略图的目标大小,并将照片以一个适当尺寸的Bitmap形式返回。我们首先从构造一个指向该缩略图的URI开始:

    /**     * Load a contact photo thumbnail and return it as a Bitmap,     * resizing the image to the provided image dimensions as needed.     * @param photoData photo ID Prior to Honeycomb, the contact's _ID value.     * For Honeycomb and later, the value of PHOTO_THUMBNAIL_URI.     * @return A thumbnail Bitmap, sized to the provided width and height.     * Returns null if the thumbnail is not found.     */    private Bitmap loadContactPhotoThumbnail(String photoData) {        // Creates an asset file descriptor for the thumbnail file.        AssetFileDescriptor afd = null;        // try-catch block for file not found        try {            // Creates a holder for the URI.            Uri thumbUri;            // If Android 3.0 or later            if (Build.VERSION.SDK_INT                    >=                Build.VERSION_CODES.HONEYCOMB) {                // Sets the URI from the incoming PHOTO_THUMBNAIL_URI                thumbUri = Uri.parse(photoData);            } else {            // Prior to Android 3.0, constructs a photo Uri using _ID                /*                 * Creates a contact URI from the Contacts content URI                 * incoming photoData (_ID)                 */                final Uri contactUri = Uri.withAppendedPath(                        Contacts.CONTENT_URI, photoData);                /*                 * Creates a photo URI by appending the content URI of                 * Contacts.Photo.                 */                thumbUri =                        Uri.withAppendedPath(                                contactUri, Photo.CONTENT_DIRECTORY);            }            /*         * Retrieves an AssetFileDescriptor object for the thumbnail         * URI         * using ContentResolver.openAssetFileDescriptor         */        afd = getActivity().getContentResolver().                openAssetFileDescriptor(thumbUri, "r");        /*         * Gets a file descriptor from the asset file descriptor.         * This object can be used across processes.         */        FileDescriptor fileDescriptor = afd.getFileDescriptor();        // Decode the photo file and return the result as a Bitmap        // If the file descriptor is valid        if (fileDescriptor != null) {            // Decodes the bitmap            return BitmapFactory.decodeFileDescriptor(                    fileDescriptor, null, null);            }        // If the file isn't found        } catch (FileNotFoundException e) {            /*             * Handle file not found errors             */        }        // In all cases, close the asset file descriptor        } finally {            if (afd != null) {                try {                    afd.close();                } catch (IOException e) {}            }        }        return null;    }

在你的代码中调用loadContactPhotoThumbnail()来获取缩略图的Bitmap对象,将结果用来设置你的QuickContactBadge中的联系人缩略图:

    ...    /*     * Decodes the thumbnail file to a Bitmap.     */    Bitmap mThumbnail =            loadContactPhotoThumbnail(mThumbnailUri);    /*     * Sets the image in the QuickContactBadge     * QuickContactBadge inherits from ImageView, so     */    mBadge.setImageBitmap(mThumbnail);

三). 添加一个QuickContactBadge到ListView中

一个QuickContactBadge是一个ListView的非常有用的控件,它会显示联系人的列表。使用QuickContactBadge为每一个联系人显示他的缩略图;当用户点击缩略图后,QuickContactBadge对话框会出现。

添加QuickContactBadge元素

首先,添加一个QuickContactBadge视图元素到你的列表项布局中。例如,如果你想要显示一个QuickContactBadge还有你检索的每个联系人的名字,将下列XML放置到一个布局文件中:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"                android:layout_width="match_parent"                android:layout_height="wrap_content">    <QuickContactBadge        android:id="@+id/quickcontact"        android:layout_height="wrap_content"        android:layout_width="wrap_content"        android:scaleType="centerCrop"/>    <TextView android:id="@+id/displayname"              android:layout_width="match_parent"              android:layout_height="wrap_content"              android:layout_toRightOf="@+id/quickcontact"              android:gravity="center_vertical"              android:layout_alignParentRight="true"              android:layout_alignParentTop="true"/></RelativeLayout>

在下面的章节中,这一文件我们称它为:contact_item_layout.xml

配置一个自定义CursorAdapter

要将一个CursorAdapter绑定到一个包含有QuickContactBadge的ListView上,自定义一个自定义的适配器,它继承自CursorAdapter。这一方法允许你在将Cursor绑定到QuickContactBadge之前,可以在Cursor内处理数据。同时这个方法还允许你将多个Cursor列绑定到QuickContactBadge上。这些方法对于一个传统的CursorAdapter而言是不可能做到的。

对于CursorAdapter的子类,你必须覆写下列方法:

CursorAdapter.newView()

填充一个新的View对象来显示列表项布局。在该方法的覆写版本中,保存布局中子View对象的句柄,包括子QuickContactBadge。通过使用这一方法,你可以避免每次你填充一个新的布局时去获取子View对象的句柄。

你必须要覆写这一方法,这样你才能获取每个自View对象的句柄。这一方法允许你在CursorAdapter.bindView()方法中控制他们的捆绑关系。

CursorAdapter.bindView()

将数据从当前的Cursor行移动到列表项布局中子View对象里。你必须覆写这一方法这样你就能同时将联系人URI和缩略图捆绑到QuickContactBadge上。而默认的实现值允许一列数据和一个View间一对一的对应关系。

下面的代码片段包含了自定义子类CursorAdapter的一个例子:

定义自定义列表适配器

定义CursorAdapter的子类,包括它的构造函数,覆写newView()和bindView():

    /**     *     *     */    private class ContactsAdapter extends CursorAdapter {        private LayoutInflater mInflater;        ...        public ContactsAdapter(Context context) {            super(context, null, 0);            /*             * Gets an inflater that can instantiate             * the ListView layout from the file.             */            mInflater = LayoutInflater.from(context);            ...        }        ...        /**         * Defines a class that hold resource IDs of each item layout         * row to prevent having to look them up each time data is         * bound to a row.         */        private class ViewHolder {            TextView displayname;            QuickContactBadge quickcontact;        }        ..        @Override        public View newView(                Context context,                Cursor cursor,                ViewGroup viewGroup) {            /* Inflates the item layout. Stores resource IDs in a             * in a ViewHolder class to prevent having to look             * them up each time bindView() is called.             */            final View itemView =                    mInflater.inflate(                            R.layout.contact_list_layout,                            viewGroup,                            false                    );            final ViewHolder holder = new ViewHolder();            holder.displayname =                    (TextView) view.findViewById(R.id.displayname);            holder.quickcontact =                    (QuickContactBadge)                            view.findViewById(R.id.quickcontact);            view.setTag(holder);            return view;        }        ...        @Override        public void bindView(                View view,                Context context,                Cursor cursor) {            final ViewHolder holder = (ViewHolder) view.getTag();            final String photoData =                    cursor.getString(mPhotoDataIndex);            final String displayName =                    cursor.getString(mDisplayNameIndex);            ...            // Sets the display name in the layout            holder.displayname = cursor.getString(mDisplayNameIndex);            ...            /*             * Generates a contact URI for the QuickContactBadge.             */            final Uri contactUri = Contacts.getLookupUri(                    cursor.getLong(mIdIndex),                    cursor.getString(mLookupKeyIndex));            holder.quickcontact.assignContactUri(contactUri);            String photoData = cursor.getString(mPhotoDataIndex);            /*             * Decodes the thumbnail file to a Bitmap.             * The method loadContactPhotoThumbnail() is defined             * in the section "Set the Contact URI and Thumbnail"             */            Bitmap thumbnailBitmap =                    loadContactPhotoThumbnail(photoData);            /*             * Sets the image in the QuickContactBadge             * QuickContactBadge inherits from ImageView             */            holder.quickcontact.setImageBitmap(thumbnailBitmap);    }

设置变量

在你的代码中,设置变量,包括一个Cursor投影,它包含了必要的那些列。

Note:

下面的代码片段使用了loadContactPhotoThumbnail()方法,这在之前的章节中该方法已经详细叙述过了。

例如:

public class ContactsFragment extends Fragment implements        LoaderManager.LoaderCallbacks<Cursor> {...    // Defines a ListView    private ListView mListView;    // Defines a ContactsAdapter    private ContactsAdapter mAdapter;    ...    // Defines a Cursor to contain the retrieved data    private Cursor mCursor;    /*     * Defines a projection based on platform version. This ensures     * that you retrieve the correct columns.     */    private static final String[] PROJECTION =            {                Contacts._ID,                Contacts.LOOKUP_KEY,                (Build.VERSION.SDK_INT >=                 Build.VERSION_CODES.HONEYCOMB) ?                        Contacts.DISPLAY_NAME_PRIMARY :                        Contacts.DISPLAY_NAME                (Build.VERSION.SDK_INT >=                 Build.VERSION_CODES.HONEYCOMB) ?                        Contacts.PHOTO_THUMBNAIL_ID :                        /*                         * Although it's not necessary to include the                         * column twice, this keeps the number of                         * columns the same regardless of version                         */                        Contacts_ID                ...            };    /*     * As a shortcut, defines constants for the     * column indexes in the Cursor. The index is     * 0-based and always matches the column order     * in the projection.     */    // Column index of the _ID column    private int mIdIndex = 0;    // Column index of the LOOKUP_KEY column    private int mLookupKeyIndex = 1;    // Column index of the display name column    private int mDisplayNameIndex = 3;    /*     * Column index of the photo data column.     * It's PHOTO_THUMBNAIL_URI for Honeycomb and later,     * and _ID for previous versions.     */    private int mPhotoDataIndex =            Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?            3 :            0;    ...

设置ListView

在Fragment.onCreate()中,实例化自定义的cursor适配器,并获得一个ListView的句柄:

    @Override    public void onCreate(Bundle savedInstanceState) {        ...        /*         * Instantiates the subclass of         * CursorAdapter         */        ContactsAdapter mContactsAdapter =                new ContactsAdapter(getActivity());        /*         * Gets a handle to the ListView in the file         * contact_list_layout.xml         */        mListView = (ListView) findViewById(R.layout.contact_list_layout);        ...    }    ...

在onActivityCreated()中,将ContactsAdapter和ListView绑定起来:

    @Override    public void onActivityCreated(Bundle savedInstanceState) {        ...        // Sets up the adapter for the ListView        mListView.setAdapter(mAdapter);        ...    }    ...

当你获取了一个包含有联系人数据的Cursor,通常是在onLoadFinished(),调用swapCursor()将Cursor数据移动到ListView。这会为联系人列表中的每一个条目显示QuickContactBadge:

    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {        // When the loader has completed, swap the cursor into the adapter.        mContactsAdapter.swapCursor(cursor);    }

当你通过一个CursorAdapter(或它的子类)将一个Cursor绑定到ListView上,并且你使用CursorLoader加载Cursor,一定要记得在onLoaderReset()的实现中清楚Cursor的引用,例如:

    @Override    public void onLoaderReset(Loader<Cursor> loader) {        // Removes remaining reference to the previous Cursor        mContactsAdapter.swapCursor(null);    }

更多相关文章

  1. 一句话锁定MySQL数据占用元凶
  2. Android版本更新时对SQLite数据库升级或者降级遇到的问题
  3. 【Android(安卓)Developers Training】 99. 获取联系人详细信息
  4. ContentProvider讲解与实例应用
  5. android之ListView的Adapter使用
  6. Android面试题(数据存储、view篇)
  7. android实现数据库和UI同步更新
  8. Android本地存储和SharedPreferences
  9. Android利用AChartEngine绘制图表

随机推荐

  1. Android中设置中文粗体的方法
  2. 友盟推送android 8.0系统不显示推送消息
  3. 编译用于Android的FFmpeg&x264
  4. Android如何进行数字签名与优化
  5. Android Wifi子系统源代码View
  6. Android控件拖动
  7. 【Android 】Prebuilt预编译
  8. RadioButton和CheckBox自定义按钮图片的
  9. Android中遇到的简单工厂模式的几种实现
  10. 2010.11.15———android spinner下拉列