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
相关产品推荐
相关产品推荐

