【Android Developers Training】 99. 获取联系

系统 1799 0

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

原文链接: http://developer.android.com/training/contacts-provider/retrieve-details.html


这节课将会展示如何获取一个联系人的详细数据,比如电子邮件地址,电话号码,等等。当用户获得一个联系人后,他会想要查看他的详细信息。你可以展示给他们所有的信息,或者只展示某一特定类型的信息,比如电子邮件地址。

这节课中,我们假设你已经有了用户选择的一行 ContactsContract.Contacts 联系人数据。在上一节课中(博客链接: http://www.cnblogs.com/jdneo/p/3674830.html )我们已经讲解了如何获取联系人列表的知识。


一). 获取一个联系人的详细信息

要获得一个联系人的所有信息,需要搜索 ContactsContract.Data 表的每一行,看是否包含有联系人的 LOOKUP_KEY 。这一列可在 ContactsContract.Data 中获得,因为Contacts Provider在 ContactsContract.Contacts 表和 ContactsContract.Data 表之间执行了一个隐式的连接。列 LOOKUP_KEY 的详细信息在上一节课中 (博客链接: http://www.cnblogs.com/jdneo/p/3674830.html 已经讲授过了。

Note:

获取某一个联系人的所有信息会降低设备的性能,因为它需要获取 ContactsContract.Data 表中所有列的数据。在你使用这一方法前要考虑到它对性能的影响。

请求权限

要从Contacts Provider中读取数据,你的应用必须具有 READ_CONTACTS 权限。要请求这一权限,在清单文件的 <manifest> 标签中添加如下子标签:

      
        <
      
      
        uses-permission 
      
      
        android:name
      
      
        ="android.permission.READ_CONTACTS"
      
      
        />
      
    

配置一个投影

根据每一行所包含的的数据类型,它可能使用一些列或很多列。另外,数据类型的不同会导致数据再不同的列中。要保证你能获得对于所有可能数据类型所对应的所有可能的列,你需要添加所有的列名到你的投影中。同时,如果要把结果 Cursor 和一个 ListView 绑定起来,要获取 Data._ID ;否则,绑定不会产生效果。同时要获取 Data.MIMETYPE 这样你就可以标示出你获得的每一行数据的类型,例如:

      
        private
      
      
        static
      
      
        final
      
       String PROJECTION =
      
        

            {

                Data._ID,

                Data.MIMETYPE,

                Data.DATA1,

                Data.DATA2,

                Data.DATA3,

                Data.DATA4,

                Data.DATA5,

                Data.DATA6,

                Data.DATA7,

                Data.DATA8,

                Data.DATA9,

                Data.DATA10,

                Data.DATA11,

                Data.DATA12,

                Data.DATA13,

                Data.DATA14,

                Data.DATA15

            };
      
    

这一投影会为 ContactsContract.Data 表的一行获取所有的列,使用在 ContactsContract.Data 类中所定义的列名。

或者,你也可以是用在 ContactsContract.Data 类中定义或者从它继承的其它列常量。注意,列 SYNC1 到列 SYNC4 是被同步适配器使用的,所以他们的数据对我们现在的应用场景而言没有用。

定义选择标准

为你的选择语句定义一个常量,它是一个保存选择语句的数组,以及一个保存对应值的变量。使用 Contacts.LOOKUP_KEY 列来寻找联系人,例如:

      
        //
      
      
         Defines the selection clause
      
      
        private
      
      
        static
      
      
        final
      
       String SELECTION = Data.LOOKUP_KEY + " = ?"
      
        ;

    
      
      
        //
      
      
         Defines the array to hold the search criteria
      
      
        private
      
       String[] mSelectionArgs = { ""
      
         };

    
      
      
        /*
      
      
        

     * Defines a variable to contain the selection value. Once you

     * have the Cursor from the Contacts table, and you've selected

     * the desired row, move the row's LOOKUP_KEY value into this

     * variable.

     
      
      
        */
      
      
        private
      
       String mLookupKey;
    

在你的选择语句中使用“?”作为占位符,能保证搜索语句是由绑定生成的而不是编译生成的。这可以防止恶意的SQL注入攻击。

定义排列顺序

为结果 Cursor 定义你期望的排列顺序。要让某一类型数据的所有行根据 Data.MIMETYPE 来排列。这一语句会让所有email的行放在一起,所有电话号码的行放在一起,等等。例如:

      
        /*
      
      
        

     * Defines a string that specifies a sort order of MIME type

     
      
      
        */
      
      
        private
      
      
        static
      
      
        final
      
       String SORT_ORDER = Data.MIMETYPE;
    

Note:

一些数据类型不使用子类,所以你不能用子类型来排序。相反的,你需要再返回的 Cursor 中进行迭代,确定当前行的数据类型,然后将使用子类型的行的数据保存起来。当你完成读cursor后,之后你就可以通过子类型排序并显示结果。

初始化加载器

通常,我们在后台线程从Contacts Provider(以及其它所有的内容提供器)获取数据。使用由 LoaderManager 类,以及 LoaderManager.LoaderCallbacks 接口所定义的加载器框架来执行后台的获取操作。

当你准备好获取行后,通过调用 initLoader() 初始化加载器框架。将一个整形标识传递给该方法;这一标志会传递给 LoaderManager.LoaderCallbacks 方法。它可以帮助你区分这些加载器,从而在一个应用中使用多个加载器。

下面的代码样例展示了如何初始化这个加载器框架:

      
        public
      
      
        class
      
       DetailsFragment 
      
        extends
      
       Fragment 
      
        implements
      
      
        

        LoaderManager.LoaderCallbacks
      
      <Cursor>
      
         {

    ...

    
      
      
        //
      
      
         Defines a constant that identifies the loader
      
      

    DETAILS_QUERY_ID = 0
      
        ;

    ...

    
      
      
        /*
      
      
        

     * Invoked when the parent Activity is instantiated

     * and the Fragment's UI is ready. Put final initialization

     * steps here.

     
      
      
        */
      
      
        

    @Override

    onActivityCreated(Bundle savedInstanceState) {

        ...

        
      
      
        //
      
      
         Initializes the loader framework
      
      

        getLoaderManager().initLoader(DETAILS_QUERY_ID, 
      
        null
      
      , 
      
        this
      
      );
    

实现 onCreateLoader()

实现 onCreateLoader() 方法,它会在你调用了 initLoader() 后被加载器框架调用。该方法返回一个 CursorLoader 。因为你在搜索 ContactsContract.Data 表,所以使用 Data.CONTENT_URI 常量作为内容URI。例如:

      
            @Override

    
      
      
        public
      
       Loader<Cursor> onCreateLoader(
      
        int
      
      
         loaderId, Bundle args) {

        
      
      
        //
      
      
         Choose the proper action
      
      
        switch
      
      
         (loaderId) {

            
      
      
        case
      
      
         DETAILS_QUERY_ID:

            
      
      
        //
      
      
         Assigns the selection parameter
      
      

            mSelectionArgs[0] =
      
         mLookupKey;

            
      
      
        //
      
      
         Starts the query
      
      

            CursorLoader mLoader =

                    
      
        new
      
      
         CursorLoader(

                            getActivity(),

                            Data.CONTENT_URI,

                            PROJECTION,

                            SELECTION,

                            mSelectionArgs,

                            SORT_ORDER

                    );

            ...

    }
      
    

实现onLoadFinished()和onLoaderReset()

实现 onLoadFinished() 方法。当Contacts Provider将查询结果返回后,加载器框架会调用 onLoadFinished() 。例如:

      
        public
      
      
        void
      
       onLoadFinished(Loader<Cursor>
      
         loader, Cursor cursor) {

        
      
      
        switch
      
      
         (loader.getId()) {

            
      
      
        case
      
      
         DETAILS_QUERY_ID:

                    
      
      
        /*
      
      
        

                     * Process the resulting Cursor here.

                     
      
      
        */
      
      
        

                }

                
      
      
        break
      
      
        ;

            ...

        }

    }
      
    

当加载器检测到结果中的数据发生了变化,那么 onLoaderReset() 方法会被调用,此时,将所有存在的 Cursor 引用设置成null来移除它们。如果你不这么做,加载器框架不会销毁老的 Cursor ,这样会导致内存泄露,例如:

      
            @Override

    
      
      
        public
      
      
        void
      
       onLoaderReset(Loader<Cursor>
      
         loader) {

        
      
      
        switch
      
      
         (loader.getId()) {

            
      
      
        case
      
      
         DETAILS_QUERY_ID:

                
      
      
        /*
      
      
        

                 * If you have current references to the Cursor,

                 * remove them here.

                 
      
      
        */
      
      
        

                }

                
      
      
        break
      
      
        ;

    }
      
    

二). 获取一个联系人的特定数据

要获取一个联系人的特定数据,比如email,和检索所有的详细数据类似,你需要做的改变仅仅是实现课程 Retrieve All Details for a Contact (博客链接: http://www.cnblogs.com/jdneo/p/3674830.html 中列出的代码:

投影

修改你的投影,使得列对应于特定的要搜索的数据类型。同时修改投影,使用在 ContactsContract.CommonDataKinds 子类中对应于数据类型的列常量名。

选择

修改选择语句,搜索对应于你的数据类型的 MIMETYPE 值。

排列顺序

因为你值使用单一的详细数据类型,所以不需要根据 Data.MIMETYPE 将返回的 Cursor 分类。

这些修改在下列章节中描述。

定义一个投影

定义你要获取的列,使用 ContactsContract.CommonDataKinds 子类中对应于数据类型的列常量名。如果你想要将 Cursor 绑定到一个 ListView 上,要确保获取“ _ID ”列。例如,要获取email数据,定义下列投影:

      
        private
      
      
        static
      
      
        final
      
       String[] PROJECTION =
      
        

            {

                Email._ID,

                Email.ADDRESS,

                Email.TYPE,

                Email.LABEL

            };
      
    

注意这一投影使用 ContactsContract.CommonDataKinds.Email 类中定义的列名,而不是在类 ContactsContract.Data 中定义的列名。使用email的特定列名可以增加代码的可读性。

在投影中,你也可以使用在 ContactsContract.CommonDataKinds 子类中定义的其它列。

定义选择标准

定义一个搜索表达式,它获取你想要的特定联系人的 LOOKUP_KEY Data.MIMETYPE 行数据。对于 MIMETYPE 的值对应的常量,用单引号(')将它括起来;否则,提供器会把常量认为是一个变量名而不是一个字符串值。你不需要为它使用一个占位符,因为你使用的是一个常量而不是一个用户提供的值。例如:

      
        /*
      
      
        

     * Defines the selection clause. Search for a lookup key

     * and the Email MIME type

     
      
      
        */
      
      
        private
      
      
        static
      
      
        final
      
       String SELECTION =
      
        

            Data.LOOKUP_KEY 
      
      + " = ?" +

            " AND " +
      
        

            Data.MIMETYPE 
      
      + " = " +

            "'" + Email.CONTENT_ITEM_TYPE + "'"
      
        ;

    
      
      
        //
      
      
         Defines the array to hold the search criteria
      
      
        private
      
       String[] mSelectionArgs = { "" };
    

定义排列顺序

为返回的 Cursor 定义一个排列顺序。因为你获得的是一个特定的数据类型,所以略过对 MIMETYPE 排序。另外,如果你正在搜索的详细数据包含有一个子类型,可以对他排序。例如,对于Email数据你可以根据 Email.TYPE 来排序:

      
        private
      
      
        static
      
      
        final
      
       String SORT_ORDER = Email.TYPE + " ASC ";
    

【Android Developers Training】 99. 获取联系人详细信息


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论