Android权限的坑
这篇是日记,反省日记。顺便吐槽下有些国产系统的权限管理的漏洞。
近日接到一个小需求---读取手机通讯录并分页传给H5。
直接上代码:
1. 权限部分
if(selfPermissionGranted(android.Manifest.permission.READ_CONTACTS)){
getUserPhoneContacts(start, size);
}else{
//申请权限
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.M) {
//6.0 以上开启
ActivityCompat.requestPermissions(BannerActivity.this,newString[]{android.Manifest.permission.READ_CONTACTS},1);
}else{ ... }
}
}
2.权限判断
//判断本app是否开启了手机联系人权限
public booleanselfPermissionGranted(String permission) {
// For Android < Android M, self permissions are always granted.
booleanresult =true;
inttargetSdkVersion =0;
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.M) {
try{
finalPackageInfo info =this.getPackageManager().getPackageInfo(
this.getPackageName(),0);
targetSdkVersion = info.applicationInfo.targetSdkVersion;
}catch(PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
if(targetSdkVersion >= Build.VERSION_CODES.M) {
// targetSdkVersion >= Android M, we can
// use Context#checkSelfPermission
result =this.checkSelfPermission(permission)
== PackageManager.PERMISSION_GRANTED;
}else{
// targetSdkVersion < Android M, we have to use PermissionChecker
result = PermissionChecker.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED;
}
}else{
//6.0以下判断
PackageManager pm = getPackageManager();
result = (PackageManager.PERMISSION_GRANTED== pm.checkPermission("android.permission.READ_CONTACTS", getPackageName()));
}
returnresult;
}
此处不得不吐槽一下,6.0以下的Android机的适配是个问题,测试了包括锤子5.1.1,小米等手机,6.0以下的机器有询问弹出窗口且点击了拒绝之后,其默认的的权限还是允许的状态。尝试了GitHub上面的AndPermission、TedPermission的开源库后,仍是如此,有些不知所以,有经验的望指教(target 是22,项目中不好改动)。
3.读取联系人操作
一开始考虑到是分页读取上传,所以就按照Contacts._ID分段读取,以为这样会很快(实际上也很快😄)。于是直接粘贴部分代码。
先贴上开始的代码:
//--------------获取手机通讯录--------------
private void getPhoneContacts(int start,int size){ //先清空之前的数据 if(list!=null){ list.clear(); }
Uri uri = ContactsContract.Contacts.CONTENT_URI; //获取ContentResolver ContentResolver contentResolver = this.getContentResolver();
//根据row查询数据,返回Cursor
String limitOffSet="limit "+start+","+size+"";
Cursor cursor = contentResolver.query(uri, null, null, null, ContactsContract.Contacts._ID+" desc "+limitOffSet);
if (cursor!=null){
while (cursor.moveToNext()){
PhoneContactsBean bean = new PhoneContactsBean();
String contactId = cursor.getString(cursor .getColumnIndex(ContactsContract.Contacts._ID)); // 获取联系人的名字 String name = cursor.getString(cursor.getColumnIndex( ContactsContract.Contacts.DISPLAY_NAME));
bean.setName(name);
// 使用ContentResolver查找联系人的电话号码
Cursor phones = mContext.getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, null, null); // 遍历查询结果,获取该联系人的多个电话号码 ArrayListphonelist = new ArrayList();
while (phones.moveToNext())
{
int j=0;
// 获取查询结果中电话号码列中数据。
String phoneNumber = phones.getString(phones
.getColumnIndex(ContactsContract
.CommonDataKinds.Phone.NUMBER));
phonelist.add(j,phoneNumber);
}
bean.setPhoneNumList(phonelist);
phones.close();
list.add(bean);
}
cursor.close();
}
}
一开始的代码,但是在测试了几十个数据的时候还不明显,于是自己写个demo给测试机的联系人列表加入了10000条数据,读取速度非常慢。问题出在查询电话号码的查询,循环的次数太多。
改进后:
public voidgetUserPhoneContacts(intstart,intsize) {
if(start ==0) {
//联系人集合
ContentResolver resolver =this.getContentResolver();
//搜索字段
String[] projection =newString[]{
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.Contacts.DISPLAY_NAME};
// 获取手机联系人
Cursor contactsCursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection,null,null,null);
if(contactsCursor !=null) {
//key: contactId,value: 该contactId在联系人集合data的index
Map contactIdMap =newHashMap<>();
while(contactsCursor.moveToNext()) {
//获取联系人的ID
intcontactId = contactsCursor.getInt(0);
//获取联系人的姓名
String name = contactsCursor.getString(2);
//获取联系人的号码
String phoneNumber = contactsCursor.getString(1);
//号码处理
String replace = phoneNumber.replace(" ","|").replace("-","").replace("+","");
//如果联系人Map已经包含该contactId
if(contactIdMap.containsKey(contactId)) {
//得到该contactId在data的index
Integer index = contactIdMap.get(contactId);
//重新设置号码数组
PhoneContactsBean bean =list.get(index);
bean.phoneNumList.add(replace);
}else{
PhoneContactsBean bean =newPhoneContactsBean();
//如果联系人Map不包含该contactId
bean.setName(name);
bean.phoneNumList.add(replace);
list.add(bean);
contactIdMap.put(contactId,list.size() -1);
}
}
//如果联系人Map不包含该contactId
contactsCursor.close();
}
}
upLoadData(list, start, size,cbMethod);
}
读取速率上明显不在一个量级上。
这个日记告诫自己,简单的问题也要自己实地的分析下,不能简单的复制粘贴了事。