You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

READ_CONTACTS权限失效:模拟器运行联系人代码时应用崩溃求助

解决读取联系人时应用崩溃的问题

咱们先从读取联系人场景最容易踩的坑开始排查,毕竟涉及权限和系统API调用,稍不注意就会导致应用崩溃:

1. 权限申请没做全

读取联系人需要READ_CONTACTS权限,而且Android 6.0(API 23)及以上必须走动态权限申请流程,只在Manifest里加权限是不够的:

  • 先确认AndroidManifest.xml里已添加权限:
<uses-permission android:name="android.permission.READ_CONTACTS" />
  • 代码里要先判断权限是否已授予,未授予则主动申请:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.READ_CONTACTS},
            REQUEST_READ_CONTACTS);
} else {
    // 权限已拿到,开始读取联系人
    fetchContacts();
}
  • 别忘了重写权限申请结果的回调方法:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_READ_CONTACTS) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            fetchContacts();
        } else {
            Toast.makeText(this, "需要读取联系人权限才能继续", Toast.LENGTH_SHORT).show();
        }
    }
}

2. 联系人读取逻辑有漏洞

从你给出的代码片段看,大概率是Cursor操作出了问题,比如没正确关闭Cursor、查询字段错误或者空指针:
给你一个稳妥的联系人读取示例:

private void fetchContacts() {
    store.clear();
    ContentResolver cr = getContentResolver();
    // 查询联系人姓名和手机号的URI
    Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
            new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                    ContactsContract.CommonDataKinds.Phone.NUMBER},
            null, null, null);

    if (cursor != null) {
        try {
            while (cursor.moveToNext()) {
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                store.add(name + "\n" + number);
            }
            // 初始化适配器并绑定ListView
            madapt = new MyAdapter(this, store);
            ListView contactListView = findViewById(R.id.your_listview_id);
            contactListView.setAdapter(madapt);
            contactListView.setOnItemClickListener(this);
        } finally {
            cursor.close(); // 必须关闭Cursor,避免内存泄漏
        }
    } else {
        Toast.makeText(this, "暂无联系人数据", Toast.LENGTH_SHORT).show();
    }
}

这里要注意:

  • 必须用ContactsContract.CommonDataKinds.Phone.CONTENT_URI来查询手机号,别用错URI
  • 一定要在finally块里关闭Cursor,否则会引发内存泄漏甚至崩溃
  • 检查你的MyAdapter是否正确实现了BaseAdapter的所有方法(比如getCount()、getView()),适配器逻辑错误也会导致ListView加载崩溃

3. 模拟器数据或布局问题

  • 模拟器里如果没有任何联系人,Cursor会为空,要是没做空判断就会触发空指针异常,所以一定要加cursor != null的判断
  • 核对布局文件里的ListView ID和代码中findViewById的ID是否一致,ID不匹配会导致ListView初始化失败崩溃

如果按上面的步骤排查后还是崩溃,建议把Logcat里的崩溃堆栈信息贴出来,能更精准定位问题~

内容的提问来源于stack exchange,提问作者Alice Kierra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:30:40