android 获取手机通讯录以及 6.0 授权

本文介绍如何使用ContentResolver从Android设备中读取手机通讯录和SIM卡联系人信息,并展示了针对Android 6.0及以上版本如何处理权限申请流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

获取手机通讯录
获取手机通讯录需要使用到 ContentProvider 的观察者 ContentResolver 来获取。
` //获取手机通讯录联系人
    ContentResolver resolver = this.getContentResolver();

    // 获取手机联系人
    Cursor phoneCursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PHONES_PROJECTION,
            null, null, null);
    if (phoneCursor != null) {
        while (phoneCursor.moveToNext()) {
            //得到手机号码
            String phoneNumber = phoneCursor.getString(PHONES_NUMBER_INDEX);
            //当手机号码为空的或者为空字段 跳过当前循环
            if (TextUtils.isEmpty(phoneNumber))
                continue;

            //得到联系人名称
            String contactName = phoneCursor.getString(PHONES_DISPLAY_NAME_INDEX);

            //得到联系人ID
            Long contactid = phoneCursor.getLong(PHONES_CONTACT_ID_INDEX);

            //得到联系人头像ID
            Long photoid = phoneCursor.getLong(PHONES_PHOTO_ID_INDEX);

            //得到联系人头像Bitamp
            Bitmap contactPhoto = null;

            //photoid 大于0 表示联系人有头像 如果没有给此人设置头像则给他一个默认的
            if (photoid > 0) {
                Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactid);
                InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(resolver, uri);
                contactPhoto = BitmapFactory.decodeStream(input);
            } else {
                contactPhoto = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
            }
            mContactsName.add(contactName);
            mContactsNumber.add(phoneNumber);
            mContactsPhonto.add(contactPhoto);
        }
        phoneCursor.close();
    }
    for (int i = 0; i < mContactsNumber.size(); i++) {
        Log.i(TAG, "电话号码: " + mContactsNumber.get(i));
    }
    for (int i = 0; i < mContactsName.size(); i++) {
        Log.i(TAG, "姓名: " + mContactsName.get(i));
    }
    Log.i(TAG, "头像的数量: " + mContactsPhonto.size());
    Log.i(TAG, "--------------------------------------------");
}`
// 获取手机 SIM 卡的联系人
`ContentResolver resolver = this.getContentResolver();
    // 获取Sims卡联系人
    Uri uri = Uri.parse("content://icc/adn");
    Cursor phoneCursor = resolver.query(uri, PHONES_PROJECTION, null, null,
            null);

    if (phoneCursor != null) {
        while (phoneCursor.moveToNext()) {

            // 得到手机号码
            String phoneNumber = phoneCursor.getString(PHONES_NUMBER_INDEX);
            // 当手机号码为空的或者为空字段 跳过当前循环
            if (TextUtils.isEmpty(phoneNumber))
                continue;
            // 得到联系人名称
            String contactName = phoneCursor
                    .getString(PHONES_DISPLAY_NAME_INDEX);

            //Sim卡中没有联系人头像

            mContactsName.add(contactName);
            mContactsNumber.add(phoneNumber);
        }

        phoneCursor.close();
    }`
关于 anroid6.0 权限完全解析
在 6.0版本 增强了用户的安全机制。涉及到用户的隐私以及安全的时候需要用户自己手动去授权。
## 检查用户是否授权
#### 这里涉及到的 API,ContextCoompat.checkSelfPermission ,主要用于检测某个权限是否已经被授予,方法返回值
` if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {
            //申请权限  第二个参数是一个 数组 说明可以同时申请多个权限
            ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_CONTACTS}, 1);
        } else {//已授权
            obtionContacts();
        }`
## 申请授权 返回授权结果
`
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == 1) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //权限申请成功
            obtionContacts();
        } else {
            Toast.makeText(MainActivity.this, "获取联系人的权限申请失败", Toast.LENGTH_SHORT).show();
        }
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

`

在Fragment中申请权限,不要使用ActivityCompat.requestPermissions, 直接使用Fragment的requestPermissions方法,否则会回调到Activity的 onRequestPermissionsResult
如果在Fragment中嵌套Fragment,在子Fragment中使用requestPermissions方 法,onRequestPermissionsResult不会回调回来,建议使用 getParentFragment().requestPermissions方法,这个方法会回调到父Fragment中的onRequestPermissionsResult,加入以下代码可以把回调透传到子Fragment
` @Override

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
List fragments = getChildFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (fragment != null) {
fragment.onRequestPermissionsResult(requestCode,permissions,grantResults);
}
}
}
}`

### 如何在Android中读取或获取手机通讯录 #### 权限申请 从 Android 6.0 (API Level 23) 开始,应用程序不仅需要在 `AndroidManifest.xml` 文件中声明权限,还需要在运行时动态请求某些敏感权限。对于访问通讯录而言,这属于危险权限组之一,因此必须通过动态方式来获得用户的授权[^1]。 以下是实现动态权限请求的一个简单例子: ```java if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); } ``` 其中 `MY_PERMISSIONS_REQUEST_READ_CONTACTS` 是一个自定义常量用于识别回调结果。 #### 查询并显示联系人姓名 一旦获得了必要的权限之后,就可以利用 ContentResolver 对象去查询设备上的联系数据表单。下面展示了一段用来提取每一个联系人的名字以及电话号码的示范代码片段: ```java ContentResolver contentResolver = getContentResolver(); Cursor contactCursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); while (contactCursor.moveToNext()) { String id = contactCursor.getString(contactCursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID)); String hasPhone = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)); if ("1".equalsIgnoreCase(hasPhone)) { Cursor phoneCursor = contentResolver.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] {id}, null); while(phoneCursor.moveToNext()){ String phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); String name = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); System.out.println(name+" "+phoneNumber); // 输出到控制台或者保存至列表变量以便后续处理 } phoneCursor.close(); } } contactCursor.close(); ``` 上述循环遍历所有具有手机号码字段存在的记录,并打印它们的名字与对应的电话号码[^2]。 #### 将结果显示于UI组件上 如果希望把取得的数据呈现在界面上,则可以借助 TextView 或 ListView 控件完成此操作。这里给出一段设置 TextView 的基础示例作为参考[^3]: ```java TextView textView = findViewById(R.id.main_list); textView.setText("Contact Name: John Doe\nPhone Number: 555-1234"); // 实际应用当中应该替换硬编码字符串为实际检索出来的值集合中的项。 ``` 另外一种更灵活的方式就是采用 Adapter 配合 Listview 展现大量条目信息,在这种情况下可能需要用到 ViewHolder 模式优化性能表现。 #### MVP架构下的交互逻辑绑定 当项目规模增大时考虑引入设计模式比如Model–View–Presenter(MVP),这样有助于分离业务逻辑和界面呈现部分使得程序结构更加清晰易于维护扩展。下面是一个简单的匿名内部类形式实例化 Presenter 并关联 View 接口的例子[^4]: ```java actionDataManager.attachView(new DeviceActionMvpView() { @Override public void onDataLoaded(List<DeviceAction> actions) {} @Override public Context getContext() { return MainActivity.this; } @Override public void showProgress(boolean show) {} }); ``` 以上即是在安卓平台上执行读取移动终端地址簿功能的主要流程及相关技术要点概述。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值