关于内容供给器: 内容供给器(Content Provider)首要用于在不同的应用程序之间完成数据同享的功用,它供给了一套完好的机制,答应一个程序拜访另一个程序中的数据,一起还能确保被访数据的安全性。目前,运用内容供给器是Android完成跨程序同享数据的标准办法。 不同于文件存储和SharedPreferences存储中的两种大局可读写操作形式,内容供给器能够挑选只对哪一部分数据进行同享,然后确保咱们程序中的隐私数据不会有泄漏的风险。

在正式开始学习内容供给器之前,咱们需求先掌握待会儿需求用到的运转时权限。

完美解决java.lang.SecurityException:Permission Denial 问题


####1.运转时权限

首先,Android所有的权限能够归成两类:一类是普通权限,一类是风险权限; 普通权限是指那些不会直接威胁到用户的安全和隐私的权限,对于这部分权限请求,体系会主动帮咱们进行授权,而不需求用户再去手动操作了,比如在BroadcastTest项目中请求的两个权限便是普通权限。 风险权限则表明那些可能会触及用户隐私,或者对设备安全性造成影响的权限,如获取设备联系人信息、定 位设备的地理位置等,对于这部分权限,咱们当在程序中请求,并有必要要由用户手动点击授权才能够,不然程序就无法运用相应的功用。

Android中有一共上百种权限,风险权限首要为以下9组24个权限,剩余的都是普通权限:

跨程序共享数据——Content-Provider-之-运行时权限解析以及申请的实现(可完美解决java-lang-SecurityExce
运用这张表格: 这张表格里边的权限可能全都是咱们没运用过的。 不过没事,咱们并不需求了解表格中每个权限的效果,只要把它当成一个参照表来检查就行了: 每逢要运用一个权限时,能够先到这张表中来查一下: 假如是归于这张表中的权限,那么就需求进行运转时权限处理; 假如不在这张表中,则在AndroidManifest.xml文件中增加权限声明即可; 以及有的时分是关于特别权限的请求,那就当检查API了;

别的留意一下,表格中每个风险权限都归于一个权限组,咱们在进行运转时权限处理时运用的是权限名,而用户一旦赞同授权了一个权限组中的任意一个权限的话,则该权限所对应的权限组中所有的其他权限也会一起被授权。

拜访developer.android.google.cn/reference/a…能够检查Android体系中完好的权限列表。

#####1.1 在程序运转时请求权限 首先新建一个RuntimePermissionTest项目; 本比如将尝试对CALL_PHONE这个权限的请求;

CALL_PHONE这个权限是编写拨打电话功用的时分需求声明的,在Android6.0体系呈现之前,拨打电话功用的完成其实十分简单,Android6.0之后因为拨打电话会触及用户手机的资费问题,因而被列为了风险权限,需求声明才可运用。

修正activity_main.xml,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.runtimepermissiontest.MainActivity">
    <Button
        android:id="@+id/make_call"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Make Call"/>
</LinearLayout>

MainActivity,增加监听,触发打电话的逻辑:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button makeCall = (Button) findViewById(R.id.make_call);
        makeCall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try{
                    Intent intent = new Intent(Intent.ACTION_CALL);
                    intent.setData(Uri.parse("tel:10086"));
                    startActivity(intent);
                }catch (SecurityException e){
                    e.printStackTrace();
                }
            }
        });
    }
}

能够看到,在按钮的点击事件中,咱们构建了一个隐式Intent, Intent 的 action 指定为 Intent.ACTION_CALL ,这是一个体系内置的打电话的动作,然后在data部分指定了协议是 tel , 号码是10086 接下来还需在AndroidManifest中声明权限:

跨程序共享数据——Content-Provider-之-运行时权限解析以及申请的实现(可完美解决java-lang-SecurityExce

    <uses-permission android:name="android.permission.CALL_PHONE" />

当然到此为止运转的时分,会呈现报错,下面需求最终一步,进行权限请求!: 咱们把刚刚的打电话逻辑封装在call()中: PS:onRequestPermissionsResult地点的包

跨程序共享数据——Content-Provider-之-运行时权限解析以及申请的实现(可完美解决java-lang-SecurityExce

代码简析:

跨程序共享数据——Content-Provider-之-运行时权限解析以及申请的实现(可完美解决java-lang-SecurityExce

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button makeCall = (Button) findViewById(R.id.make_call);
        makeCall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.
                permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){
                    ActivityCompat.requestPermissions(MainActivity.this, new
                        String[]{ Manifest.permission.CALL_PHONE}, 1);
                }else {
                    call();
                }
            }
        });
    }
    private void call() {
        try{
            Intent intent = new Intent(Intent.ACTION_CALL);
            intent.setData(Uri.parse("tel:10086"));
            startActivity(intent);
        }catch (SecurityException e){
            e.printStackTrace();
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode){
            case 1:
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    call();
                }else{
                    Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
        }
    }

代码具体讲解: 上面的代码是请求运转时权限的完好流程,下面咱们来具体解析一下;

运转时权限的核心便是在程序运转过程中由用户授权咱们去履行某些风险操作,程序是不能够私行做主去履行这些风险操作的;

因而,第一步便是要先借助于**ContextCompa.checkSelfPermission()**办法,判别用户是不是现已给过咱们授权了。 checkSelfPermission()办法接收两个参数,第一个参数是Context,第二个参数是具体的权限名;

  • 比如打电话的权限名便是Manifest.permission.CALLPHONE, 然后咱们运用办法的返回值和PackageManager.PERMISSION_GRANTED做比较: 相等就说明用户现已授权, 不等就表明用户没有授权。

  • 假如现已授权,就直接履行拨打电话的封装办法call(); 假如没有授权,则需求调用ActivityCompat.requestpermissions()办法来向用户请求授权, requestpermissions()办法接收3个参数, 第一个参数要求是Activity的实例, 第二个参数是一个String数组,把要请求的权限名放在数组中即可, 第三个参数是请求码,只要是唯一值就能够了,这儿传入了1。

  • 调用完了requestpermissions()办法之后,体系会弹出一个权限请求的对话框,然后用户能够挑选赞同或回绝咱们的权限请求, 不论是哪种成果,最终都会回调到onRequestPermissionsResult()办法中, 而授权的成果则会封装在grantResuIts参数傍边。 到这儿判别一下最终的授权成果, 假如用户赞同就调用call()办法来拨打电话, 假如用户回绝则放弃操作并弹出一条失利提示;

下面运转程序,点击按钮,会弹出对话框:

跨程序共享数据——Content-Provider-之-运行时权限解析以及申请的实现(可完美解决java-lang-SecurityExce
假如点击回绝,则会弹出Toast:
跨程序共享数据——Content-Provider-之-运行时权限解析以及申请的实现(可完美解决java-lang-SecurityExce
假如点击答应,则成功进入到拨打电话界面:
跨程序共享数据——Content-Provider-之-运行时权限解析以及申请的实现(可完美解决java-lang-SecurityExce
在这之后,咱们就成功进入拨打电话界面了,并且至此用户现已完成了授权,之后再点击MakeCall按钮就不会再弹出权限请求对话框了,而是能够直接拨打电话。 所以留意一下这儿,用户随时都能够手动将颁发程序的风险权限进行封闭, 进人Settings→Apps→RuntimePermissionTest→Permissions进行操作即可,界面如图:

跨程序共享数据——Content-Provider-之-运行时权限解析以及申请的实现(可完美解决java-lang-SecurityExce
在这儿便能够手动开关风险权限了:
跨程序共享数据——Content-Provider-之-运行时权限解析以及申请的实现(可完美解决java-lang-SecurityExce