45. 【Android教程】内容提供者 - Content Provider

本节学习最后一个 Android 组件——内容提供者。顾名思义,它可以用来给其他的 App 提供各种内容,比如 Android 自带的短信、联系人、日历等等都是一个普通的 App,当你需要这些内容的时候,就可以向它们的 Content Provider 发起请求,然后拿到相应的数据。

1. 内容提供者的定义

照旧,首先看看官方解释:

Content providers are one of the primary building blocks of Android applications, providing content to applications. They encapsulate data and provide it to applications through the single ContentResolver interface. A content provider is only required if you need to share data between multiple applications. For example, the contacts data is used by multiple applications and must be stored in a content provider. If you don’t need to share data amongst multiple applications you can use a database directly via android.database.sqlite.SQLiteDatabase.
When a request is made via a ContentResolver the system inspects the authority of the given URI and passes the request to the content provider registered with the authority. The content provider can interpret the rest of the URI however it wants. The UriMatcher class is helpful for parsing URIs.

文档解释略长,这里用自己的话简要描述一发:

Content Provider 是 Android 四大组件之一,通过它可以向其他 App 提供数据。当收到其他 App 的数据请求时,会有一个 Content Resolver 接口统一对请求进行处理。数据请求通过 URI 的形式发起,每一次请求都需要带上 URI,Content Resolver 非常灵活并且可控性很强,在这里我们可以对来访者做鉴权,然后根据权限的不同给予不同敏感级别的数据,甚至可以对部分 App 拒绝提供数据。Content Provider 对数据的管理方式并不关心,可以采用 DataBase、文件、远程服务端等等 Android 支持的任何一种形式,整个工作流程如下:

2. 为什么需要内容提供者

首先我们聊聊 Content Provider 存在的意义,在 Android 中每个 App 运行于一个独立的进程,而不同进程之间一般是无法直接通信的,所以一个 App 里的数据不能直接共享给其他 App 使用,这就会让很多功能难以实现。
在 Android 系统中我们可以很简单的创建 DataBase 来管理我们的数据,但是出于安全性的考虑,DataBase 只能在 App 内部使用,App 之间是无法共享内存的。因此,为了能够方便的将自己的数据共享出去,Android 系统引入了 Content Provider 组件,让我们可以和其他的 App 很方便的进行数据交换,甚至可以用来做 IPC(进程间通信),这就是内容提供者存在的意义。

不适合的使用场景:
当你使用了内容提供者,就表示你的数据是对外暴露的,所以这是一个相对敏感的操作,很多 App 的漏洞都是由于 Content Provider 使用不当导致的,所以这里需要多加注意。
Content Provider 不仅仅可以很方便的对其他 App 提供数据,当然也可以给 App 内部其他模块、或者 App 的其他进程提供数据,在多人、多业务合作的场景下使用 Content Provider 确实很便利。但是要注意的是,如果共享的数据仅仅是一个 App 私有的数据,最好不要使用 Content Provider。

3. Content Provider 相关概念

在编写 Content Provider 之前,我们先来熟悉几个概念:

3.1 Content URI

Content URI 可以用来让 provider 唯一标识一个数据,它包括四个部分:

  • Scheme: Content Provider 的 Scheme 是固定的字符串——“content”
  • Authority: provider 的唯一标识,我们通过“Authority”字段来从众多的 Content Provider 中找到我们想要的那个。
  • Path: path 字段帮助我们描述出我们想要的最具体的数据。比如我们想要查询通话记录,可以通过不同的 path 来查询具体的“未接来电”、“播出来电”、“已接来电”等等。
  • ID: 数字类型的可选字段,在一些特殊场景下可以使用 ID 来区分不同的类别。

3.2 身份鉴权

在 Content Resolver 中使用对请求者的身份进行鉴权,通过 URI 中的 Authority 字段我们可以区分出不同的请求者。然后根据请求者的 path 字段和 ID 字段(如果有 ID)我们能够精准的知道它想要的数据,最后可以根据它的权限等级来给它提供相应的数据。

4. Content Provider 的常用操作

常用操作基本上就是下面四种,和数据库非常类似:

  1. 查询(Querying):
    查询某个 Content Provider 支持的所有数据对象
  2. 删除(Delete):
    从 Content Provider 的数据库中删除具体的数据对象
  3. 更新(Update):
    更新数据对象
  4. 插入(Insert):
    插入一个新的数据对象
  5. onCreate():
    在 provider 被创建的时候回调

5. Content Provider 使用示例

和 Broadcast 类似,Android 系统也为我们预置了很多必备的 Content Provider,我们来学习一下如何使用。

5.1 读取短信收件箱

Android 系统中短信也是一个 App,为了方便其他 App 读取短信(比如接收验证码),短信提供了一个 Content Provider 接口供我们使用,当然读取短信属于敏感操作,必须添加以下权限:

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

在 Android 6.0 以前只需要静态注册权限即可,但是这个年代应该没有多少 Android 6.0 以下的机型了。在 6.0 之后我们还需要在代码中动态申请权限,然后通过content://sms/来查询短信消息,代码如下:


package com.emercy.myapplication;

import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends Activity implements View.OnClickListener {

    private static final String TAG = "ContentProvider";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.get_sms).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            int hasReadSmsPermission = checkSelfPermission(Manifest.permission.READ_SMS);
            if (hasReadSmsPermission != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.READ_SMS}, 100);
                return;
            }
        }

        Uri uri = Uri.parse("content://sms/");
        ContentResolver resolver = getContentResolver();
        //获取的是哪些列的信息
        Cursor cursor = resolver.query(uri, new String[]{"address", "date", "type", "body"}, null, null, null);
        while (cursor.moveToNext()) {
            String address = cursor.getString(0);
            String date = cursor.getString(1);
            String type = cursor.getString(2);
            String body = cursor.getString(3);
            Log.d(TAG, "地址:" + address);
            Log.d(TAG, "时间:" + date);
            Log.d(TAG, "类型:" + type);
            Log.d(TAG, "内容:" + body);
        }
        cursor.close();
    }
}

contentView 的布局代码就不贴了,只需要一个 Button 即可。在 onClick 方法中我们首先申请权限,此时手机会弹出一个权限申请的弹窗,入剩下:

点击同意之后就可以观察 Logcat 了,过滤 Tag 为 ContentProvider,结果如下:

这样就能够顺利读取出短信相关的信息了。

5.2 读取联系人

其他的代码和读取短信一样,修改的部分就是onClick()中的部分,主要是权限申请和数据读取,修改 onClick() 中的代码如下:

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            int hasReadSmsPermission = checkSelfPermission(Manifest.permission.READ_CONTACTS);
            if (hasReadSmsPermission != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 100);
                return;
            }
}

ContentResolver resolver = getContentResolver();
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
Cursor cursor = resolver.query(uri, null, null, null, null);
while (cursor.moveToNext()) {
            String cName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
            String cNum = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            Log.d(TAG, "姓名:" + cName);
            Log.d(TAG, "号码:" + cNum);
        }
cursor.close();

然后在 AndroidManifest.xml 中加入读取联系人的权限:

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

第一次点击的时候同样会弹出以下权限申请弹出,授予之后即可拿到具体的联系人信息。

掌握了这两种 Content Provider 的使用,其余的像新增联系人、查询具体联系人等等其实都是换汤不换药,核心思路就是两步:1、申请权限(Android 6.0 以上需要动态申请);2、通过 URI 读取数据。

6. 小结

本节学习最后一个 Android 组件,它的功能是为其他 App 提供相关的数据,让数据可以在不同 App、不同进程之间相互共享,但是要注意的是它的适用场景,一定只是在向其他 App 输出数据的时候用,为了避免数据泄露出现安全风险,其他场景要慎用。使用 Content Provider 首先关注一下改数据是否需要申请权限,然后查询到该数据的 URI,通过拼接URI就可以完成数据的获取了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/573370.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C/C++ 入门(7)vector类(STL)

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;C 请多多指教&#xff01; 目录 一、标准库中的vector 1、了解 2、vector常用接口 二、vector的实现 1、框架 2、构造、析构函数 3、操作函数 三 、问题 1、由于赋值而引起的浅拷贝 2、因为类没…

【linux】多路径|Multipath I/O 技术

目录 简略 详细 什么是多路径? Multipath安装与使用 安装 使用 Linux下multipath软件介绍 附录 配置文件说明 其他解 简略 略 详细 什么是多路径? 普通的电脑主机都是一个硬盘挂接到一个总线上&#xff0c;这里是一对一的关系。 而到了分布式环境&#xff0c;主机和存储网络连…

普冉PY32F071单片机简单介绍,QFN64 48封装,支持 8 * 36 / 4 * 40 LCD

PY32F071单片机是一款基于32 位 ARM Cortex - M0内核的微控制器&#xff0c;由普冉半导体推出。PY32F071可广泛应用于各种嵌入式系统中&#xff0c;包括消费类电子产品、工业自动化、医疗设备等领域。PY32F071系列单片机具有低功耗、高性能和丰富的外设接口等特点&#xff0c;适…

生物制药企业在选择文件摆渡平台时,最应该关注哪些功能?

生物制药是以数据为核心生产力的企业&#xff0c;数据的重要性体现在药物研发、生产优化、销售和市场营销、决策支持以及合规要求等多个方面。有效地管理和利用数据&#xff0c;对于提升企业的竞争力、降低风险、提高产品质量和满足市场需求具有重要意义。 为保护数据安全&…

KEITHLEY(吉时利)2440源测量单位(SMU)数字源表

KEITHLEY(吉时利&#xff09;2440源测量单位&#xff08;SMU)数字源表 主要特性 50W 时性能高达 5A / 40V0.012&#xff05; 基本测量精度&#xff0c;具有 6 位分辨率10pA / 100nV 测量分辨率与 KickStart 软件结合使用美国2440吉时利keithley数字源表特点 2400系列提供宽动…

亚信安慧AntDB:高效与稳定

亚信安慧AntDB正致力于验证数据库软硬件全自主可控的可行性&#xff0c;并将其应用于运营商核心的交易场景&#xff0c;以替代国外商业解决方案。为了实现这一目标&#xff0c;亚信安慧AntDB的研发团队不断进行技术创新和实践探索。 该数据库以自主研发的技术为基础&#xff0…

C语言 流程图与伪代码 缩减

本文 我们来说说流程图 伪代码和代码缩进 这些可以让我们在后面书写复杂逻辑时 不会感到 繁琐或逻辑混乱 流程图(Flowchart) 是用以算法、工作流或流程的一种框图表示&#xff0c;它以不同类型的框代表不同种类的步骤&#xff0c;每两个步骤之间则以箭头连接。 流程图是程序…

《飞吧龙骑士》新版本“龙神祭”盛大开启,引领骑士团战

热游圈消息&#xff1a;五一假期临近&#xff0c;备受瞩目的手游《飞吧龙骑士》迎来重大更新——“龙神祭”新版本正式开启。在此次更新中&#xff0c;首个蓄力炮UR龙——绮舞的巫女千代烬惊艳登场&#xff0c;为玩家们带来前所未有的燃情体验。同时&#xff0c;全新骑士团战玩…

当你看到一份更心仪的工作时,先冷静冷静,看看这篇文章

01 无法构建自己的城堡&#xff1f;那就挖一条护城河 人活一辈子&#xff0c;在职业生涯领域&#xff0c;你总得要搭建一座属于自己的城堡&#xff0c;否则拼死拼活&#xff0c;到最后你拿到一点蝇头小利&#xff0c;为别人做嫁衣。而当别人的梦想进行曲不需要你合奏或者伴奏时…

从现在开始:让AI写代码,你只负责敲tab键

如果你是一名程序员&#xff0c;你一定有过这样的经历&#xff1a;在编写代码的时候&#xff0c;突然遇到了一个棘手的问题&#xff0c;需要花费大量的时间去查找资料、尝试不同的解决方案&#xff0c;甚至有时候还需要去问同事或者在网上寻求帮助。这样的情况不仅会浪费你的时…

【算法刷题 | 贪心算法03】4.25(最大子数组和、买卖股票的最佳时机|| )

文章目录 4.最大子数组和4.1题目4.2解法一&#xff1a;暴力4.2.1暴力思路4.2.2代码实现 4.3解法二&#xff1a;贪心4.3.1贪心思路4.3.2代码实现 5.买卖股票的最佳时机||5.1题目5.2解法&#xff1a;贪心5.2.1贪心思路5.2.2代码实现 4.最大子数组和 4.1题目 给你一个整数数组 n…

Linux中DHCP原理与配置

目录 一.DHCP的原理 1.DHCP的简要概述 2.DHCP的优点 3.DHCP的分配方式 4.DHCP的租约过程 5.DHCP服务 6.可分配的地址信息主要包括 二.DHCP同一网段分配地址实验 windows命令 一.DHCP的原理 1.DHCP的简要概述 DHCP&#xff08;Dynamic Host Configuration Protocol&a…

讯鹏智慧公厕系统解决方案新升级,大不同!

在城市建设和公共服务不断发展的今天&#xff0c;公厕作为重要的基础设施&#xff0c;其质量和管理水平直接影响着人们的生活体验。然而&#xff0c;当前公厕普遍存在着一些问题&#xff0c;如卫生状况不佳、设施老化、管理不便等。为了解决这些问题&#xff0c;讯鹏智慧公厕系…

牛客NC209 最短无序连续子数组【中等 数组,双指针 C++/Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/d17f4abd1d114617b51e951027be312e 思路 解题思路 1、方法1&#xff0c;排序对比&#xff1a;将数组按升序排序&#xff0c;然后与原数组对照&#xff0c;从哪里开始变化到哪里结束变化的数组就是答案。 2、 方…

图像处理技术与应用(二)

图像处理技术与应用入门 椒盐噪声 椒盐噪声&#xff0c;也称为脉冲噪声&#xff0c;是一种常见的数字图像噪声。它通常表现为图像中随机出现的白色&#xff08;椒&#xff09;或黑色&#xff08;盐&#xff09;像素点&#xff0c;这些像素点在图像上呈现为黑白杂点。椒盐噪声…

云计算革新:以太网 Scale-UP 网络为 GPU 加速赋能

谈谈基于以太网的GPU Scale-UP网络 Intel Gaudi-3 采用 RoCE 互联技术&#xff0c;促进了 Scale-UP 解决方案。业界专家 Jim Keller 倡导以太网替代 NVLink。Tenstorrent 成功应用以太网实现片上网络互联。RoCE 和以太网已成为互联解决方案的新兴趋势&#xff0c;为高性能计算提…

前端H5动态背景登录页面(下)

最近正好有点儿时间&#xff0c;把之前没整理完的前端动态背景登录页面给整理一下&#xff01;这是之前的连接前端H5动态背景登录页面&#xff08;上&#xff09;&#xff0c;这主要是两个登陆页面&#xff0c;一个彩色气泡&#xff0c;一个动态云朵&#xff0c;感兴趣的可以点…

关爱通丨从AIGC到硅基人同事:人工智能迭代重塑HR管理策略

2024年&#xff0c;一股创新的浪潮悄无声息地席卷了全球&#xff0c;推动了人工智能领域的重大突破。Sora视频模型的惊艳发布&#xff0c;成为了这一创新浪潮的标志性事件。 Sora这个名字源自日语中的“空”&#xff08;そら sora&#xff09;&#xff0c;象征着天空的无限广阔…

机器学习作业3____决策树(CART算法)

目录 一、简介 二、具体步骤 样例&#xff1a; 三、代码 四、结果 五、问题与解决 一、简介 CART&#xff08;Classification and Regression Trees&#xff09;是一种常用的决策树算法&#xff0c;可用于分类和回归任务。这个算法由Breiman等人于1984年提出&#xff0c;它…

sorensen索伦森电源维修XRF系列程控电源XRF600-4

AMETEK直流电源产品有两种类型&#xff1a;固定量程类型和自动量程类型。 固定量程电源是经济型的&#xff0c;输出范围为传统的矩形范围。 自动量程电源&#xff0c;在满输出功率的基础上&#xff0c;扩展了电流和电压的输出范围&#xff0c;使其能够满足更广泛的测试需求&am…
最新文章