目录
在学习内容提供器值之前,我们需要先掌握另外一个非常重要的知识——Android运行时权限,因为内容提供器实例会使用到运行时权限的功能。当然不光是内容提供器,以后我们的开发过程中,也会经常用到运行时权限,因此我们必须牢牢掌握。
运行时权限
1、Android的权限机制详解
(1)、普通权限:指的是那些不会直接威胁到用户的安全和隐私的权限,对这部分权限的申请,系统会自动帮我们进行授权,而不需要用户再去手动操作了。
(2)、危险权限:则表示那些可能会触及用户或者设备安全性造成影响的权限,如获取设备联系人信息,定位设备地理位置等,对这部分权限申请,必须要由用户手动点击授权才可以,否则程序就无法使用相应的功能。
下表列出了Android中所有危险的权限,一共是9组24个权限。
权限动态申请
新建一个RequestContacts项目,用于读取联系人。
1. 首先在联系人中随意添加几个姓名及其电话
2. 在activity_main.xml文件中新建一个ListView用于显示读取到的联系人
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/list_contacts"
/>
</LinearLayout>
3. 在MainActivity.java中加入如下代码:
实现显示联系人的逻辑:
public class MainActivity extends AppCompatActivity {
private ArrayAdapter<String> adapter;
private ListView contactView;
private List<String> contactList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
contactView = findViewById(R.id.list_contacts);
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, contactList);
contactView.setAdapter(adapter);
}
}
实现动态申请权限的逻辑:
检查是否有相应的权限需要调用 ContextCompat.checkSelfPermission() 方法,该方法接收两个参数,第一个是Context,第二是具体的权限名。根据应用是否具有相应权限,此方法会返回 PERMISSION_GRANTED 或 PERMISSION_DENIED 。
requestPermissions() 则用于申请权限。
ActivityCompat.requestPermissions() 和Activity.requestPermissions()的参数略有区别。ActivityCompat.requestPermissions()接收三个参数,第一个是Activity的实例;第二个是要申请的所有权限,以数组方式传入;第三个是requestCode申请码,需要是从0开始的唯一整数值。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
...
// request app runtime permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
== PackageManager.PERMISSION_GRANTED) {
readContacts();
} else {
requestPermissions(new String[]{ Manifest.permission.READ_CONTACTS }, 1);
}
}
}
调用了完requestPermissions()之后,系统会弹出一个权限申请的对话框,用户可以选择或者拒绝权限申请,无论结果如何,都会回调onRequestPermissionsResult()方法,重写该方法,用于处理用户的不同选择。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (grantResults == null || grantResults.length == 0) {return;}
switch (requestCode) {
case 1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
readContacts();
} else {
Log.d(PKG + TAG, "onRequestPermissionsResult: You Denied the Permission");
Toast.makeText(this, "You Denied the Permission", Toast.LENGTH_SHORT).show();
}
break;
default:
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
然后处理读取联系人的逻辑。代码如下:
private void readContacts() {
Cursor cursor = null;
try {
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.
Phone.CONTENT_URI, null, null, null, null);
if (null != cursor) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndexOrThrow(
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = cursor.getString(cursor.getColumnIndexOrThrow(
ContactsContract.CommonDataKinds.Phone.NUMBER));
contactList.add(name + ": " + phoneNumber);
}
adapter.notifyDataSetChanged();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != cursor) {cursor.close();};
}
}
最后,别忘了即使是动态申请权限也需要在AndroidManifest.xml文件中加入相关权限声明。
<uses-permission android:name="android.permission.READ_CONTACTS" />
接下来我们学习同时申请几个权限的简单方法:
public void askPermission(){//申请权限
try {
List<String> permissionList = new ArrayList<>();
if (ContextCompat.checkSelfPermission(SuixinWeatherActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ContextCompat.checkSelfPermission(SuixinWeatherActivity.this,Manifest.permission.READ_PHONE_STATE )
!= PackageManager.PERMISSION_GRANTED){
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if (ContextCompat.checkSelfPermission(SuixinWeatherActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE )
!= PackageManager.PERMISSION_GRANTED){
permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (!permissionList.isEmpty()){
String[] permissions = permissionList.toArray(new String[permissionList.size()]);
ActivityCompat.requestPermissions(SuixinWeatherActivity.this,permissions,1);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0) {
for(int result : grantResults){
if (result != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "必须所有权限都同意才能使用本应用!", Toast.LENGTH_SHORT).show();
finish();
return;
}
}
}else {
Toast.makeText(this, "发生未知错误!", Toast.LENGTH_SHORT).show();
finish();
}
}
}
同时在AndroidMenifest.xml文件中添加如下权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-
askPermission()
方法首先创建一个空的权限列表permissionList
,用于存储需要请求的权限。 -
使用
ContextCompat.checkSelfPermission()
方法检查应用程序是否已经被授予了特定权限。如果权限未被授予,则将该权限添加到permissionList
中。 -
如果
permissionList
不为空,将其转换为字符串数组permissions
,然后使用ActivityCompat.requestPermissions()
方法请求权限。该方法会显示权限请求对话框,让用户决定是否授予权限。请求码参数为1
,可用于在onRequestPermissionsResult()
方法中进行识别。 -
onRequestPermissionsResult()
方法是权限请求的回调方法,当用户对权限请求作出响应时会被调用。 -
在
onRequestPermissionsResult()
方法中,首先检查请求码requestCode
是否与之前请求的一致。 -
如果
grantResults
数组的长度大于 0,表示用户已经做出了权限请求的响应。然后遍历grantResults
数组,检查每个权限的授权结果。 -
如果有任何一个权限未被授予(
PackageManager.PERMISSION_GRANTED
),则显示一个提示消息,并且关闭当前的活动。 -
如果
grantResults
数组的长度为 0,表示发生了未知错误,显示一个错误提示消息,并且关闭当前的活动。