Android第一行代码-内容提供器(ContextProvider、ContextResolver)

跨程序共享数据–探究内容提供器

内容提供器简介(Android实现跨程序共享数据的标准方式)

内容提供器主要用于在不同的应用程序之间实现数据共享的功能,允许一个程序访问另一个程序的数据,同时可保证被访数据的安全性。

运行时权限

Android6.0系统中引用了运行时权限这个功能,从而更好的保护了用户的安全和隐私。

Android权限机制详解

用户设备的安全性主要在以下两个方面得到了保护:

  • 如果用户在低于6.0系统的设备上安装该程序,会在安装界面给出提醒,这样用户就可以清楚地知晓该程序一共申请了哪些权限。
  • 用户可以随时在应用程序管理界面查看任意一个程序的权限申请情况。

Android开发团队在6.0系统中加入了运行时权限,也就是说,用户不需要在安装软件的时候一次性授权所有申请的权限,而是可以在软件的使用过程中再对某一项权限申请进行授权。比如一款相机在运行时申请地理权限定位权限,就算我拒绝了这个权限,但是我依然可以使用这个应用的其他功能,而不是像之前那样直接无法安装。

并不是所有的权限都需要在运行时申请,Android现在讲所有的权限分为两类

  • 普通权限:不会直接威胁到用户的安全和隐私的权限,对于这部分权限,系统会帮我们进行授权。
  • 危险权限:可能会触及用户隐私,或者对设备安全性造成影响的权限。必须用户手动点击授权。
危险权限

在这里插入图片描述

每次需要使用一个权限时,先到这张表中查一下,如果属于该表,需要进行运行时权限出来,否则只需要在AndroidManifest.xml文件中添加一下权限声明就可以了。

需要注意一下,表格中每个危险权限都属于一个权限组,我们在进行运行时权限处理时使用的是权限名,但是一旦用户同意授权了,那么该权限所对应的权限组中的其他权限也会同事被授权。

Android系统中完整的权限列表

在程序运行时申请权限

判断用户是否已经给我们授权,是用的是ContextCompat.checkSelfPermission()方法(compat 兼容,网络),两个参数:

  • 1、Context
  • 2、权限名

通过调用ActivityCompat.requestPermissions()方法来向用户申请授权,requestPermission()方法接收3个参数:

  • 第一个参数要求是Activity的实例
  • 第二个参数是String数组,我们把要申请的权限名放在数组中即可。
  • 第三个参数是请求码,只要是唯一值就可以。

调用完requestPermissions()之后,系统会弹出一个权限申请的对话框,然后用户可以选择同意或者拒绝我们的权限申请,不论是哪种结果,最终都会回调到onRequestPermissionResult方法中,授权结果会放在grantResults参数中。

package com.example.runtimepermissiontest;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

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) {
                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) {
        //super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        super.onRequestPermissionsResult(requestCode, permissions, 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:
        }
    }
}

访问其他程序中的数据

两种用法:

  • 1、使用现有的内容提供器来读取和操作相应程序中的数据。
  • 2、创建自己的内容提供器给我们程序的数据提供外部访问接口。

ContentResolver的基本用法(通过Context中的getContentResolver()方法来获取该类的实例)

如果要访问内容提供器中共享的数据,就一定要借助ContentResolver类(Resolver解析器),可以通过Context中的getContentResolver()方法来获取该类的实例。

ContentResolver提供了一系列方法用于对数据进行CRUD。分别是insert、delete、update、query四个方法。

不同于SQLiteDatabase,ContentResolver中的增删改查都是不接受表名参数的,而是使用一个Uri参数代替。内容URI给内容提供器中的数据建立唯一标识符,由两部分组成:authority和path。authority是用于对不同的应用程序做区分的,一般避免冲突,都是采用包名的方式来命名,

比如包名为com.example.app,那么该程序对应的authority就可以命名为com.example.provider,path是用于对同一应用程序中的不同表做区分的。通常都会添加到authority的后面,比如数据库中存在一张表table1,那么内容URI的最标准的格式写法如下:

  • content://com.example.app.provider/table1

ContentResolver中的增删改查方法都接收Uri对象作为参数,因为如果使用表名的话,系统将无法得知我们期望访问的是哪个应用程序里的表。

查询

如:

Uri uri = Uri.parse("content://com.example.app.provider/table1");
Cursor cursor = getContentResolver().query(uri,projection,selection,selectionArgs,sortOrder);

参数解释:
在这里插入图片描述

插入
ContentValues values = new ContentValues();
values.put("column1",text);
values.put("column2",1);
getContentResolver().insert(uri,valyes);
更新
ContentValues values = new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"column1=? and column2=?" ,new String[]{"text",1});
删除
getContentResolver().delete(uri,"column2=?",new String[]{"1"});

创建自己的内容提供器

创建内容提供器的步骤(继承ContentProvider)

可以通过新建一个类去继承ContentProvider的方式来创建一个自己的内容提供器。

public class MyProvider extends ContentProvider{
	@Override
	public boolean onCreate(){
		return false;
	}
	@Override
	public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder){
		return null;
	}
	
	@Override
	public Uri insert(Uri uri,ContentValues values){
		return null;
	}
	@Override
	public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs){
		return 0;
	}
	
	@Override
	public int delete(Uri uri,String selection,String[] selectionArgs){
		return 0;
	}
	@Override
	public String getType(Uri uri){
		return null;
	}
	
}

这六个方法介绍:

  • 1、onCreate()方法,初始化内容提供器的时候调用,通常会在这里完成对数据库的创建和升级等操作,返回true表示内容提供器初始化成功,返回false表示失败。注意:只有当ContentResolver尝试访问我们程序中的数据的时候,内容提供器才会被初始化。
  • 2、query()方法:从内容提供器中查询数据,使用uri参数来缺点查询哪张表,projection参数用于确定查询哪些列,selection和selectionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序。查询的结果放在Cursor对象中返回。
  • 3、insert()方法:向内容提供器中插入一条数据,使用uri参数来确定要添加到的表,待添加的数据保存在values参数中,查询的结果保存在Cursor对象中返回。
  • 4、update():更新内容提供器中已有的数据,使用uri参数来确定更新哪张表中的数据,新数据保存在values参数中,selection金额selectionArgs用于约束更新哪些行,受影响的行数将作为返回值返回。
  • 5、delete():从内容提供器中删除数据,使用uri参数来确定删除哪一个表中的数据,selection和selectionArgs参数用于约束删除哪些行,被删除的行数将作为返回值返回。
  • 6、getType():根据传入的内容URI来返回相应的MIME类型。

一个标准的URI写法是这样的:

  • content://com.example.app.provider/table1表示调用方期望访问的是com.example.app这个应用的table1表中的数据。
  • URI的后面加id,content://com.example.app.provider/table1/1表示调用方期望访问的是com.example.app这个应用中id为1的数据

内容URI的格式主要就是以上两种,以路径结果表示期望访问该表中的所有数据,以id结果表示期望访问该表中拥有相应id的数据。我们可以使用通配符的方式来分别匹配这两种格式的内容URI,规则如下:

  • *:表示匹配任意长度的任意字符
  • #:表示匹配任意长度的数字

所以一个匹配任意表的URI格式就可以写成:

  • content://com.example.app.provider/*

一个能匹配table1表中任意一行数据的内容URI格式就可以写成:

  • content://com.example.app.provider/table1/#

Git时间-版本控制工具进阶

忽略文件

Git提供了一种可配性很强的机制来运行用户将制定的文件或目录排除在版本控制之外,他会检查代码仓库的目录下是否存在一个名为.gitignore的文件。如果存在的话,就去一行行读取这个文件中的内容。并把每一行指定的文件或目录排除在版本控制之外。

查看修改内容

  • 查看文件修改情况:git status
  • 查看更改内容:git diff,如果只想查看某个文件的更改内容,git diff app/src/java/com/example/providertest/MainActivity.java

撤销未提交的修改(git checkout、git reset)

  • 当代码还未add时,使用checkout命令可以撤销修改。git checkout app/src/main/java/com/example/providertest/MainActivity.java
  • 当已添加文件,要对其进行取消添加,然后才可以撤回提交,取消添加的命令是reset命令。gir reset HEAD app/src/java/com/example/providertest/MainActivity.java

查看提交记录(git log)

git log:命令查看历史提交信息。
当提交记录非常多的时候,如果我们只想查看其中一条记录,可以在命令行中指定记录的id,并加上-l参数表示我们只想看到一行记录。
在这里插入图片描述

而如果想要查看这条记录具体修改了什么内容,可以在命令中加入-p参数,命令如下:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值