Content Provider(内容提供器)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性。目前,使用内容提供器是Android实现跨程序共享数据的标准方式。
不同于文件存储和SharedPreferences存储中的两种全局可读写操作模式,内容提供器可以选择只对哪一部分数据进行共享,从而保证程序中的隐私数据不会有泄漏的风险。

文章目录

  • 运行时权限
    • Android权限机制
    • 运行时申请权限
  • Content Provider
    • 使用现有Content Provider
    • 自定义Content Provider

运行时权限

Android 6.0以前,Android的权限机制在保护用户安全和隐私等方面起到的作用比较有限,Android开发团队在Android 6.0系统中引用了运行时权限这个功能,从而更好地保护了用户的安全和隐私。

Android权限机制

当应用程序要访问系统相关信息(例如网络状态)或是设置系统设置,这会涉及用户设备的安全性,必须要在AndroidManifest.xml文件中添加权限声明,否则程序会崩溃

<!--添加权限-->
<uses-permission android:name="android.permission.READ_CONTACTS"/>

声明权限之后用户在两个方面得到了保护:

  1. 如果用户在低于6.0系统的设备上安装程序,会在安装界面上提醒用户程序所要获取的权限,这样用户就可以清楚的知道该程序一共申请了那些权限,从而决定是否要安装程序。
  2. 用户可以随时在应用程序管理界面查看任意一个程序的权限申请情况

虽然Android系统通过权限保护了用户的信息安全,但是很多常用软件普遍存在滥用权限的情况,不管最后到底用不用,先把申请权限了。Android开发团队意识到了这个问题,于是在6.0系统中加入了运行时权限功能。用户不需要在安装软件的时候一次性授权所有申请的权限,而是可以在软件的使用过程中再对某一项权限申请进行授权。

Android将所有的权限归成了两类:

  • 普通权限:指那些不会直接威胁到用户的安全和隐私的权限,对于这部分权限申请,系统会自动帮用户进行授权,而不需要用户再去手动操作。
  • 危险权限:指那些可能会触及用户隐私或者对设备安全性造成影响的权限,对于这部分权限申请,必须要由用户手动点击授权才可以,否则程序就无法使用相应的功能。

这样做可以避免用户繁琐的授权。

Android中有一共有上百种权限,危险权限总共就几个,除了危险权限之外,剩余的就都是普通权限。Android中所有的危险权限,一共是9组24个权限,如下图所示

用户一旦同意授权了,那么该权限所对应的权限组中所有的其他权限也会同时被授权。每当要使用一个权限时,可以先到这张表中来查一下,如果是属于这张表中的权限,那么就需要进行运行时权限处理,如果不在这张表中,那么只需要在AndroidManifest.xml文件中添加一下权限声明就可以。

运行时申请权限

运行时权限的核心就是在程序运行过程中由用户授权去执行某些危险操作,程序不可以擅自做主去执行这些危险操作的。第一步就是要先判断用户是不是已经授权了,通过ContextCompat.checkSelfPermission() 方法实现。

public static int checkSelfPermission(@NonNull Context context, @NonNull String permission)

checkSelfPermission() 方法接收两个参数:

  • Context context:context对象(Activity等)
  • String permission:具体的权限名(打电话的权限:Manifest.permission.CALL_PHONE)

通过checkSelfPermission() 方法的返回值与PackageManager.PERMISSION_GRANTED 做比较,相等就说明用户已经授权,不等就表示
用户没有授权。

如果没有授权的话,则需要调用ActivityCompat.requestPermissions() 方法来向用户申请授权。

public static void requestPermissions(final @NonNull Activity activity, final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode)

requestPermissions() 方法接收3个参数:

  • Activity activity:Activity的实例
  • String[] permissions:要申请的权限名放在数组中
  • int requestCode:请求码,要求是唯一值

调用完了requestPermissions() 方法之后,系统会弹出一个权限申请的对话框,然后用户可以选择同意或拒绝程序的权限申请,不论是哪种结果,最终都会回调到onRequestPermissionsResult() 方法中,而授权的结果则会封装在grantResults参数当中。
相关代码如下:

     if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {//没有授权,先执行授权操作ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1);} else {//若已经授权,执行其他操作}//回调方法@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {//授权与否都会调用这个方法,用回调方法执行程序相应的逻辑}

若用户想回收赋予程序的权限,可以在设置中回收程序的权限。

Content Provider

Content Provider的用法一般有两种:

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

一个应用程序通过内容提供器对其数据提供了外部访问接口,那么任何其他的应用程序就都可以对这部分数据进行访问

使用现有Content Provider

要访问内容提供器中共享的数据,需要借助ContentResolver类,可以通过Context中的getContentResolver() 方法获取到该类的实例。
ContentResolver中提供了一系列的方法用于对数据进行CRUD操作:

  • insert():添加数据
  • update():更新数据
  • delete():删除数据
  • query():查询数据

这些操作与SQLiteDatabase类似。ContentResolver中的CRUD方法都是不接收表名参数的,而是使用一个Uri参数代替,这个参数被称为内容URI。
内容URI给内容提供器中的数据建立了唯一标识符,它主要由两部分组成:

  • authority:用于对不同的应用程序做区分的,一般为了避免冲突,都会采用程序包名的方式来进行命名
  • path:用于对同一应用程序中不同的表做区分的,通常都会添加到authority的后面

除此之外,还需要在URI字符串前添加协议声明,使其能够被识别成内容URI,内容URI最标准的格式写法如下:

content://cn.chenjianlink.android.contactstest/table

在得到了内容URI字符串之后,需要将它解析成Uri对象才可以作为参数传入,调用Uri.parse() 方法,就可以将内容URI字符串解析成Uri 对象:

Uri uri = Uri.parse("content://cn.chenjianlink.android.contactstest/table")

使用Uri 对象来查询表中的数据:

Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);

query() 方法中的参数如下表所示,与SQLiteDatabase类似:

查询完成后返回的是一个Cursor 对象,这时可以将数据从Cursor对象中逐个读取出来了。通过移动游标的位置来遍历Cursor 的所有行,然后再取出每一行中相应列的数据,相关代码如下:

if (cursor != null) {while (cursor.moveToNext()) {String column1 = cursor.getString(cursor.getColumnIndex("column1"));int column2 = cursor.getInt(cursor.getColumnIndex("column2"));}cursor.close();
}

对Content Provider增加操作如下所示:

ContentValues values = new ContentValues();
values.put("column1", "text");
values.put("column2", 1);
getContentResolver().insert(uri, values);

将待添加的数据组装到ContentValues中,然后调用ContentResolver的insert() 方法,将Uri和ContentValues作为参数传入。

对Content Provider修改操作如下所示:

ContentValues values = new ContentValues();
values.put("column1", "");
getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new String[] {"text", "1"});

对Content Provider删除操作如下所示:

getContentResolver().delete(uri, "column2 = ?", new String[] { "1" });

自定义Content Provider

过新建一个类去继承ContentProvider 的方式来创建一个自己的内容提供器。ContentProvider 类中有6个抽象方法,在使用子类继承它的时候,需要将这6个方法全部重写:

public class MyProvider extends ContentProvider {@Overridepublic boolean onCreate() {return false;}@Overridepublic Cursor query(Uri uri, String[] projection, String selection, String[]selectionArgs, String sortOrder) {return null;}@Overridepublic Uri insert(Uri uri, ContentValues values) {return null;}@Overridepublic int update(Uri uri, ContentValues values, String selection, String[]selectionArgs) {return 0;}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {return 0;}@Overridepublic String getType(Uri uri) {return null;}
}
  • onCreate():初始化Content Provider的时候调用。返回true 表示内容提供器初始化成功,返回false 则表示失败。
  • query():从Content Provider中查询数据。使用uri 参数来确定查询哪张表,projection 参数用于确定查询哪些列,selection 和selectionArgs 参数用于约束查询哪些行,sortOrder 参数用于对结果进行排序,查询的结果存放在Cursor对象中返回。
  • insert():向Content Provider中添加一条数据。使用uri 参数来确定要添加到的表,待添加的数据保存在values 参数中。添加完成后,返回一个用于表示这条新记录的URI
  • update():更新Content Provider中已有的数据。使用uri 参数来确定更新哪一张表中的数据,新数据保存在values 参数中,selection 和selectionArgs 参数用于约束更新哪些行,受影响的行数将作为返回值返回
  • delete():从Content Provider中删除数据。使用uri 参数来确定删除哪一张表中的数据,selection 和selectionArgs 参数用于约束删除哪些行,被删除的行数将作为返回值返回。
  • getType():根据传入的内容URI来返回相应的MIME类型。

每一个方法都会带有Uri 这个参数,这个参数也正是调用Content Resolver的增删改查方法时传递过来的。
一个标准的内容URI写法如下:

content://cn.chenjianlink.android.contactstest/table

可以在这个内容URI的后面加上一个id,表示调用方期望访问的是cn.chenjianlink.android.contactstest这个应用的table表中id为1的数据

content://cn.chenjianlink.android.contactstest/table/1

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

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

借助UriMatcher这个类就可以轻松地实现匹配内容URI的功能,UriMatcher中提供了一个addURI() 方法,这个方法接收3个参数:

public void addURI(String authority, String path, int code)

  • String authority
  • String path
  • int code:自定义代码

调用UriMatcher的match() 方法时,就可以将一个Uri 对象传入,返回值是某个能够匹配这个Uri对象所对应的自定义代码,利用这个代码,就可以判断出调用方期望访问的是哪张表中的数据了。

对于getType() 方法。它是所有的内容提供器都必须提供的一个方法,用于获取Uri 对象所对应的MIME类型。一个内容URI所对应的MIME字符串主要由3部分组成,Android对这3个部分做了如下格式规定:

  • 必须以vnd 开头
  • 如果内容URI以路径结尾,则后接android.cursor.dir/ ,如果内容URI以id结尾,则后接android.cursor.item/
  • 最后接上vnd.<authority>.<path>

对于content://cn.chenjianlink.android.contactstest/table 这个内容URI,它所对应的MIME类型就可以写成:

vnd.android.cursor.dir/vnd.cn.chenjianlink.android.contactstest.table

对于content://cn.chenjianlink.android.contactstest/table/1 这个内容URI,它所对应的MIME类型就可以写成:

vnd.android.cursor.item/vnd.cn.chenjianlink.android.contactstest.table

自定义Content Resolver需要在AndroidManifest.xml文件中注册才可以使用,相关代码如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="cn.chenjianlink.android.contactstest"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/AppTheme">...<providerandroid:name=".MyProvider"android:authorities="cn.chenjianlink.android.contactstest"android:enabled="true"android:exported="true"></provider></application>
</manifest>

在<application>标签中添加<provider>标签,<provider>标签属性如下:

  • android:name:指定MyProvider的类名
  • android:authorities:指定MyProvider的authority
  • android:enabled:表示是否启用这个内容提供器
  • android:exported:表示是否允许外部程序访问自定义的内容提供器

Android学习羁绊之Content Provider相关推荐

  1. Android应用程序组件Content Provider简要介绍和学习计划

    在Android系统中,Content Provider作为应用程序四大组件之一,它起到在应用程序之间共享数据的作用,同时,它还是标准的数据访问接口.前面的一系列文章已经分析过Android应用程序的 ...

  2. Android应用程序组件Content Provider的启动过程源代码分析(1)

             通过前面的学习,我们知道在Android系统中,Content Provider可以为不同的应用程序访问相同的数据提供统一的入口.Content Provider一般是运行在独立的进 ...

  3. Android应用程序组件Content Provider的共享数据更新通知机制分析

    在Android系统中,应用程序组件Content Provider为不同的应用程序实现数据共享提供了基础设施,它主要通过Binder进程间通信机制和匿名共享内存机制来实现的.关于数据共享的另一个 话 ...

  4. Android应用程序组件Content Provider在应用程序之间共享数据的原理分析(1)

             在Android系统中,不同的应用程序是不能直接读写对方的数据文件的,如果它们想共享数据的话,只能通过Content Provider组件来实现.那么,Content Provide ...

  5. Android四大组件之Content Provider

    Android四大组件之Content Provider 作者:白璐 日期:2020/2/24 文章目录 Android四大组件之Content Provider 概述 内容提供器(Content P ...

  6. Android应用程序组件Content Provider的启动过程源代码分析(6)

        Step 17. ActivityThread.installProvider         这个函数定义在frameworks/base/core/java/android/app/Act ...

  7. Android应用程序组件Content Provider的共享数据更新通知机制分析(3)

            3. 数据更新通知的发送过程        在前面这篇文章Android应用程序组件Content Provider应用实例介绍的应用程序Acticle中,当调用ArticlesAda ...

  8. Android应用安全之Content Provider安全

    android平台提供了Content Provider,将一个应用程序的指定数据集提供给其它应用程序.这些数据可以存储在文件系统.SQLite数据库中,或以任何其它合理的方式存储.其他应用可以通过C ...

  9. Android学习羁绊之Activity

    原文链接:Android学习羁绊–>Activity Activity是Android系统的四大组件之一,Activity是用户可操作的可视化界面,为用户提供一个完成操作指令的窗口,一个Acti ...

最新文章

  1. 测试sql语句执行时间
  2. linux 串口驱动(二)初始化 【转】
  3. 解决报表部署时数据源存在不能替换的问题
  4. python requirements.txt_python_requirements.txt使用
  5. 多线程 并发编程(一)
  6. python json文件遍历所有key、value 及替换key对于的value
  7. Python 技巧总结
  8. 将excel中的数据导入到oracle数据库中
  9. python转go_使用Go获取Python版本
  10. 163的在线编辑器简析和配置使用
  11. php arcsin,三角函数在线计算器
  12. Win10安装乌班图18双系统
  13. tplink 虚拟服务器没有https,tplink虚拟服务器设置
  14. 面向对象程序设计实践(C++)——二维向量
  15. mysql 2038年问题_64位Ubuntu系统的时间戳,2038年问题
  16. 18.10.9 实验吧----分道扬镳
  17. 自动控制原理知识点梳理——5.线性系统的频域分析法
  18. 客流统计分析系统增强售楼处、4S店飞单管理能力
  19. swt java 内嵌ActiveX控件
  20. 大便、小便与放屁 --引用

热门文章

  1. oracle删除表数据的两种的方式
  2. 宁波经贸学校:钉钉宜搭护航学生成长,探索职业教育数字化新思路
  3. 浏览器支持linux版本下载软件,Linux版Edge浏览器下载
  4. 分发糖果的程序设计代码_糖果为您设计的颤动交互引擎
  5. Python智慧农业之将数据存储在表格中并从图表中获取见解,基于 Google 表格和 Neo4j 中维护伴随植物知识图谱(教程含源码)
  6. mysql utf8mb4 配置_MySQL数据库UTF8mb4设置
  7. jQuery面试题汇总
  8. 第二届中国·沈阳国际少儿时装周盛大举行
  9. oracle使用impdp导入方法,oracle expdp导出和impdp导入使用方法
  10. 独立站即web3.0,国家“十四五“规划要求企业建数字化网站!