Android_LoaderManager获取联系人

故事概况:
小农在开发的时候队长叫本人封装一个工具类,直接调用就能调起系统通讯录,选择人员后,把电话号码带回到UI……..
于是故事开始了….

  • 写一个静态的类用来调用方法
  • 封装进入系统联系人界面的方法如下
// 进入系统通讯录界面
 public static void gotoSystemContact(Activity activityContext, int requestCode) {
        Intent moblieIntent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
        activityContext.startActivityForResult(moblieIntent, requestCode);
    }
  • 写一个获取联系人内容的方法,
/**
     * get contact phone
     *
     * @param cursor cursor
     * @return all phone nums
     */
    private static List<String> getContactPhone(Activity activityContext, Cursor cursor) {
        ArrayList<String> arrayList = new ArrayList<String>();
        Cursor phone = null;
        try {
            int phoneColumn = cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);
            int phoneNum = cursor.getInt(phoneColumn);
            if (phoneNum > 0) {
                int idColumn = cursor.getColumnIndex(ContactsContract.Contacts._ID);
                String contactId = cursor.getString(idColumn);
                phone = activityContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId, null, null);
                if (phone != null && phone.moveToFirst()) {
                    for (; !phone.isAfterLast(); phone.moveToNext()) {
                        int index = phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
                        int typeindex = phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
                        int phone_type = phone.getInt(typeindex);
                        String phoneNumber = phone.getString(index).trim();
                        arrayList.add(phoneNumber);
                    }
                }

            }
        } catch (Exception e) {
        }
        if (phone != null && !phone.isClosed()) {
            phone.close();
        }
        return arrayList;
    }
  • 解析联系人去除空格乱七八糟的如下方法
/**
     * onActivityResult call the method get the contact phone num
     *
     * @param activityContext activity
     * @param data            onActivityresult data
     * @return phoneNum
     */
    public static String getContactResult(Activity activityContext, Intent data) {
        String phoneNum = "";
        Cursor cursor = null;
        try {
            if (data != null) {
                Uri contactData = data.getData();
                if (contactData != null) {
                    cursor = activityContext.managedQuery(contactData, null, null, null, null);
                }
                if (cursor != null && cursor.moveToFirst()) {
                    String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    List<String> numbers = getContactPhone(activityContext, cursor);
                    if (numbers != null && numbers.size() > 0) {
                        String[] mPhoneNumbers = new String[numbers.size()];
                        for (int i = 0; i < numbers.size(); i++) {
                            String number = numbers.get(i);
                            String newNumber = number.replaceAll("[^\\d]", "");
                            mPhoneNumbers[i] = newNumber;
                        }
                        phoneNum = mPhoneNumbers[0];
                    }
                }
            }
        } catch (Exception e) {
        }
        return phoneNum;
    }

就是这个方法,看到没有很顺利的返回了 phoneNum,但是数据库的coucor没有关闭,一个严谨的程序员怎么能忍受游标不关闭呢,其实我是能忍受的…..队长不能接受,必须要关闭 关闭能带来的问题是什么,第一次能获取到联系人号码,然后第二次执行的时候 在UI的onActivityResult里面会崩溃并且报游标关闭错误….

如下图:这里写图片描述

但是如果你不关闭游标的话…..传说中的代码不严谨,内存泄漏什么的一堆,于是就的改…牺牲点app内存和一点点的代码不严谨你完成这个功能就需要一个操作,
ctr + D 删除关闭代码就行了…

但是这不允许,第一用了过时的API,第二游标必须关闭,所以只能修改实现方式

  1. 新的实现方法,采用LoaderManager来完成,
    我们修改下获取手机号的方法如下
    /**
     * onActivityResult call the method get the contact phone num
     *
     * @param activityContext     activity
     * @param data                data
     * @param phoneNumGetListener phone num callback
     */
    public static void getContactResult(final Activity activityContext, Intent data, final OnPhoneNumGetListener phoneNumGetListener) {
        if (data != null) {
            final Uri contactData = data.getData();
            if (contactData != null) {
                activityContext.getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
                            @Override
                            public Loader<Cursor> onCreateLoader(int id, Bundle args) {
                                CursorLoader cursorLoader = new CursorLoader(activityContext);
                                cursorLoader.setUri(contactData);
                                return cursorLoader;
                            }

                            @Override
                            public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
                                if (data != null && data.moveToFirst()) {
                                    String name = data.getString(data.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                                    List<String> numbers = getContactPhone(activityContext, data);
                                    if (numbers != null && numbers.size() > 0) {
                                        String[] mPhoneNumbers = new String[numbers.size()];
                                        for (int i = 0; i < numbers.size(); i++) {
                                            String number = numbers.get(i);
                                            String newNumber = number.replaceAll("[^\\d]", "");
                                            mPhoneNumbers[i] = newNumber;
                                        }
                                        if (phoneNumGetListener != null) {
                                            phoneNumGetListener.getPhoneNum(mPhoneNumbers[0]);
                                        }
                                    }
                                    data.close();
                                    // when get data do not forget destoryloader
                                    activityContext.getLoaderManager().destroyLoader(0);
                                }
                            }

                            @Override
                            public void onLoaderReset(Loader<Cursor> loader) {

                            }
                        }

                );
            }
        }

    }

这里我们传入了获得到手机号的一个异步回调,这就是LoaderManager的最大的区别,cursor = activityContext.managedQuery(contactData, null, null, null, null);

这方法是同步的,而且这个方法是过时的……

这样我们获取手机号的方法和解析就放到了 onLoadFinished里面

代码基本就这么多,activity里面只需要这样既可

  @Override
    protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == MOBILE_REQUEST_CODE) {
            ATContactUtilLoadManager.getContactResult(this, data, new ATContactUtilLoadManager.OnPhoneNumGetListener() {
                @Override
                public void getPhoneNum(String num) {
                    phoneNum.setText("loadmanager得到的>>>> " + num);
                }
            });
        }
    }

这样我们就能通过loadmanager拿到手机号了,关键的是curcor关闭了,任务完成了…..可能是最近看乔布斯传魔怔了,要是以前的脾气,早就pk起来了 ,删除一句代码就能解决干嘛费劲搞这个loadermanager
反过来想想加入 谷歌删除了过时的API. 或者由于你这个游标没关闭造成的内存泄漏正好达到crash的内存上限..罪过就大了..从自我做起吧,写一篇博客记录下今天的内容,两种工具类喜欢的可以看下
完整代码如下:
**

  • 第一种普通方法代码

**

package com.asiatravel.atjardemo.utils;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;

import java.util.ArrayList;
import java.util.List;

/**
 * <pre>use like this</pre>
 * <pre>1, call gotoSystemContact</pre>
 * <pre>2, onActivityResult call getContactResult</pre>
 *
 * Created by jsion on 16/5/10.
 */
public class ATContactUtilNormal {
    private ATContactUtilNormal() {
    }

    public static void gotoSystemContact(Activity activityContext, int requestCode) {
        Intent moblieIntent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
        activityContext.startActivityForResult(moblieIntent, requestCode);
    }

    /**
     * onActivityResult call the method get the contact phone num
     *
     * @param activityContext activity
     * @param data            onActivityresult data
     * @return phoneNum
     */
    public static String getContactResult(Activity activityContext, Intent data) {
        String phoneNum = "";
        Cursor cursor = null;
        try {
            if (data != null) {
                Uri contactData = data.getData();
                if (contactData != null) {
                    cursor = activityContext.managedQuery(contactData, null, null, null, null);
                }
                if (cursor != null && cursor.moveToFirst()) {
                    String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    List<String> numbers = getContactPhone(activityContext, cursor);
                    if (numbers != null && numbers.size() > 0) {
                        String[] mPhoneNumbers = new String[numbers.size()];
                        for (int i = 0; i < numbers.size(); i++) {
                            String number = numbers.get(i);
                            String newNumber = number.replaceAll("[^\\d]", "");
                            mPhoneNumbers[i] = newNumber;
                        }
                        phoneNum = mPhoneNumbers[0];
                    }
                }
            }
        } catch (Exception e) {
        }
        return phoneNum;
    }


    /**
     * get contact phone
     *
     * @param cursor cursor
     * @return all phone nums
     */
    private static List<String> getContactPhone(Activity activityContext, Cursor cursor) {
        ArrayList<String> arrayList = new ArrayList<String>();
        Cursor phone = null;
        try {
            int phoneColumn = cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);
            int phoneNum = cursor.getInt(phoneColumn);
            if (phoneNum > 0) {
                int idColumn = cursor.getColumnIndex(ContactsContract.Contacts._ID);
                String contactId = cursor.getString(idColumn);
                phone = activityContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId, null, null);
                if (phone != null && phone.moveToFirst()) {
                    for (; !phone.isAfterLast(); phone.moveToNext()) {
                        int index = phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
                        int typeindex = phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
                        int phone_type = phone.getInt(typeindex);
                        String phoneNumber = phone.getString(index).trim();
                        arrayList.add(phoneNumber);
                    }
                }

            }
        } catch (Exception e) {
        }
        if (phone != null && !phone.isClosed()) {
            phone.close();
        }
        return arrayList;
    }
}

**

  • 第二种,loadermanager实现

**

package com.asiatravel.atjardemo.utils;

import android.app.Activity;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;

import java.util.ArrayList;
import java.util.List;

/**
 * <pre>use like this</pre>
 * <pre>1, call gotoSystemContact</pre>
 * <pre>2, onActivityResult call getContactResult</pre>
 *
 * Created by jsion on 16/5/10.
 */
public class ATContactUtilLoadManager {
    private ATContactUtilLoadManager() {
    }

    public static void gotoSystemContact(Activity activityContext, int requestCode) {
        Intent moblieIntent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
        activityContext.startActivityForResult(moblieIntent, requestCode);
    }

    /**
     * onActivityResult call the method get the contact phone num
     *
     * @param activityContext activity
     * @param data            onActivityresult data
     * @return phoneNum
     */
    public static void getContactResult(final Activity activityContext, Intent data, final OnPhoneNumGetListener phoneNumGetListener) {
        if (data != null) {
            final Uri contactData = data.getData();
            if (contactData != null) {
                activityContext.getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
                            @Override
                            public Loader<Cursor> onCreateLoader(int id, Bundle args) {
                                CursorLoader cursorLoader = new CursorLoader(activityContext);
                                cursorLoader.setUri(contactData);
                                return cursorLoader;
                            }

                            @Override
                            public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
                                if (data != null && data.moveToFirst()) {
                                    String name = data.getString(data.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                                    List<String> numbers = ATContactUtilLoadManager.getContactPhone(activityContext, data);
                                    if (numbers != null && numbers.size() > 0) {
                                        String[] mPhoneNumbers = new String[numbers.size()];
                                        for (int i = 0; i < numbers.size(); i++) {
                                            String number = numbers.get(i);
                                            String newNumber = number.replaceAll("[^\\d]", "");
                                            mPhoneNumbers[i] = newNumber;
                                        }
                                        if (phoneNumGetListener != null) {
                                            phoneNumGetListener.getPhoneNum(mPhoneNumbers[0]);
                                        }
                                    }
                                    data.close();
                                    activityContext.getLoaderManager().destroyLoader(0);
                                }
                            }

                            @Override
                            public void onLoaderReset(Loader<Cursor> loader) {

                            }
                        }

                );
            }
        }
    }


    /**
     * get contact phone
     *
     * @param cursor cursor
     * @return all phone nums
     */
    public static List<String> getContactPhone(Activity activityContext, Cursor cursor) {
        ArrayList<String> arrayList = new ArrayList<String>();
        Cursor phone = null;
        try {
            int phoneColumn = cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);
            int phoneNum = cursor.getInt(phoneColumn);
            if (phoneNum > 0) {
                int idColumn = cursor.getColumnIndex(ContactsContract.Contacts._ID);
                String contactId = cursor.getString(idColumn);
                phone = activityContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId, null, null);
                if (phone != null && phone.moveToFirst()) {
                    for (; !phone.isAfterLast(); phone.moveToNext()) {
                        int index = phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
                        int typeindex = phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
                        int phone_type = phone.getInt(typeindex);
                        String phoneNumber = phone.getString(index).trim();
                        arrayList.add(phoneNumber);
                    }
                }

            }
        } catch (Exception e) {
//            ATLogUtil.e(e.toString());
        }
        if (phone != null && !phone.isClosed()) {
            phone.close();
        }
        return arrayList;
    }

    public interface OnPhoneNumGetListener {
        void getPhoneNum(String phoneNum);
    }
}
<think>好的,用户想在Android获取手机联系人的示例代码。我需要先回忆一下Android开发中访问联系人的基本流程。首先,Android系统使用ContentProvider来管理联系人数据,所以需要通过ContentResolver来查询。 首先,用户需要声明权限。访问联系人需要读取联系人的权限,所以应该在AndroidManifest.xml中添加READ_CONTACTS权限。这一点很重要,否则应用会因为没有权限而崩溃。 接下来是查询联系人数据。通常使用ContactsContract.CommonDataKinds.Phone这个URI来获取联系人的电话号码和名称。查询时需要用ContentResolver的query方法,指定要查询的列,比如DISPLAY_NAME和NUMBER。 然后处理查询返回的Cursor对象。这里需要注意,Cursor使用后必须关闭,否则会有资源泄漏的问题。通常的做法是在finally块中关闭,或者在Kotlin中使用use扩展函数自动关闭。 用户可能需要一个ListView或RecyclerView来展示联系人列表。这就需要将查询到的数据放入适配器中,比如SimpleCursorAdapter或者自定义的适配器。不过示例代码中可能使用ArrayAdapter来简化,将数据转换为字符串列表。 此外,还需要考虑Android版本差异。比如在Android 6.0及以上,需要在运行时请求权限,而不仅仅是声明。所以代码中应该包含检查权限的逻辑,如果没有权限则请求用户授权。 用户提供的参考代码中有一个getView方法,看起来像是自定义适配器的实现。不过那个例子可能比较旧,或者使用了不同的方式,比如直接读取联系人数据并显示在ListView中。需要确保示例代码符合当前的开发实践,比如使用LoaderManager异步加载数据,避免在主线程中进行耗时操作。 综合这些点,我需要提供一个基本的示例,包括权限声明、查询联系人、处理Cursor以及展示数据。同时要提醒用户关于运行时权限的问题,并给出适配器的使用建议。可能还需要指出常见问题,比如URI的选择,是否需要过滤重复的联系人等,但示例中可以保持简单,只获取姓名和号码。</think>在Android获取手机联系人需要通过`ContentResolver`查询系统联系人数据库,以下是实现步骤和示例代码: ### 一、权限声明 在`AndroidManifest.xml`中添加权限: ```xml <uses-permission android:name="android.permission.READ_CONTACTS"/> ``` ### 二、获取联系人核心代码 ```java private void getContacts() { ContentResolver resolver = getContentResolver(); Cursor cursor = resolver.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, new String[]{ ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER }, null, null, null ); List<String> contacts = new ArrayList<>(); if (cursor != null && cursor.moveToFirst()) { do { String name = cursor.getString(0); String number = cursor.getString(1); contacts.add(name + "\n" + number); } while (cursor.moveToNext()); cursor.close(); } // 显示到ListView ListView listView = findViewById(R.id.listView); ArrayAdapter<String> adapter = new ArrayAdapter<>( this, android.R.layout.simple_list_item_1, contacts); listView.setAdapter(adapter); } ``` ### 三、运行时权限处理(Android 6.0+) ```java if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_CODE_READ_CONTACTS); } else { getContacts(); } ``` ### 四、注意事项 1. 使用`CommonDataKinds.Phone`可获取有电话号码的联系人 2. 需要处理`Cursor`为空的情况 3. 推荐在子线程执行查询操作(已简化的示例中未体现) 4. 实际开发建议使用`CursorLoader`实现异步加载[^1] : 参考联系人数据加载的最佳实践:`public View getView(int paramInt, View paramView, ViewGroup paramViewGroup)`是典型适配器实现方式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值