深入分析 Android ContentProvider (八)

文章目录

    • 深入分析 Android ContentProvider (八)
    • ContentProvider 高级使用及最佳实践案例分析(续)
      • 1. 深入了解跨应用数据共享
        • 示例:跨应用数据共享的完整实现
        • 1. 定义权限
        • 2. 定义 ContentProvider
        • 3. ContentProvider 实现
      • 2. 实践案例:音乐播放器的播放列表管理
        • 案例概述
        • 1. 数据库设计
        • 2. ContentProvider 实现
      • 3. 总结

深入分析 Android ContentProvider (八)

ContentProvider 高级使用及最佳实践案例分析(续)

1. 深入了解跨应用数据共享

跨应用数据共享是 ContentProvider 的一个重要功能,它允许应用之间安全地共享数据。为此,我们需要定义清晰的权限和 URI 结构,以确保数据在不同应用之间安全传输。

示例:跨应用数据共享的完整实现
1. 定义权限

AndroidManifest.xml 中定义权限:

<permissionandroid:name="com.example.myapp.READ_DATA"android:protectionLevel="signature" />
<permissionandroid:name="com.example.myapp.WRITE_DATA"android:protectionLevel="signature" />
2. 定义 ContentProvider

AndroidManifest.xml 中定义 ContentProvider,并设置权限:

<providerandroid:name=".MyContentProvider"android:authorities="com.example.myapp.provider"android:exported="true"android:readPermission="com.example.myapp.READ_DATA"android:writePermission="com.example.myapp.WRITE_DATA" />
3. ContentProvider 实现

实现 ContentProvider 并处理权限:

public class MyContentProvider extends ContentProvider {private static final String AUTHORITY = "com.example.myapp.provider";private static final String BASE_PATH = "data";public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);private static final int DATA = 1;private static final int DATA_ID = 2;private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);static {uriMatcher.addURI(AUTHORITY, BASE_PATH, DATA);uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", DATA_ID);}private SQLiteDatabase database;@Overridepublic boolean onCreate() {DatabaseHelper dbHelper = new DatabaseHelper(getContext());database = dbHelper.getWritableDatabase();return true;}@Nullable@Overridepublic Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,@Nullable String[] selectionArgs, @Nullable String sortOrder) {if (getContext().checkCallingOrSelfPermission("com.example.myapp.READ_DATA") != PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Permission denied");}switch (uriMatcher.match(uri)) {case DATA:return database.query(DatabaseHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);case DATA_ID:selection = DatabaseHelper.COLUMN_ID + "=?";selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};return database.query(DatabaseHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);default:throw new IllegalArgumentException("Unknown URI: " + uri);}}@Nullable@Overridepublic Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {if (getContext().checkCallingOrSelfPermission("com.example.myapp.WRITE_DATA") != PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Permission denied");}long id = database.insert(DatabaseHelper.TABLE_NAME, null, values);getContext().getContentResolver().notifyChange(uri, null);return ContentUris.withAppendedId(CONTENT_URI, id);}@Overridepublic int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {if (getContext().checkCallingOrSelfPermission("com.example.myapp.WRITE_DATA") != PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Permission denied");}int rowsDeleted;switch (uriMatcher.match(uri)) {case DATA:rowsDeleted = database.delete(DatabaseHelper.TABLE_NAME, selection, selectionArgs);break;case DATA_ID:selection = DatabaseHelper.COLUMN_ID + "=?";selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};rowsDeleted = database.delete(DatabaseHelper.TABLE_NAME, selection, selectionArgs);break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}getContext().getContentResolver().notifyChange(uri, null);return rowsDeleted;}@Overridepublic int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {if (getContext().checkCallingOrSelfPermission("com.example.myapp.WRITE_DATA") != PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Permission denied");}int rowsUpdated;switch (uriMatcher.match(uri)) {case DATA:rowsUpdated = database.update(DatabaseHelper.TABLE_NAME, values, selection, selectionArgs);break;case DATA_ID:selection = DatabaseHelper.COLUMN_ID + "=?";selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};rowsUpdated = database.update(DatabaseHelper.TABLE_NAME, values, selection, selectionArgs);break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}getContext().getContentResolver().notifyChange(uri, null);return rowsUpdated;}@Nullable@Overridepublic String getType(@NonNull Uri uri) {switch (uriMatcher.match(uri)) {case DATA:return "vnd.android.cursor.dir/vnd.com.example.myapp.provider.data";case DATA_ID:return "vnd.android.cursor.item/vnd.com.example.myapp.provider.data";default:throw new IllegalArgumentException("Unknown URI: " + uri);}}
}

2. 实践案例:音乐播放器的播放列表管理

案例概述

假设我们正在开发一个音乐播放器应用,需要管理和共享播放列表。每个播放列表包含多个音乐文件。我们将使用 ContentProvider 来管理播放列表,并确保其他应用也可以访问这些播放列表。

1. 数据库设计
public class DatabaseHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "music.db";private static final int DATABASE_VERSION = 1;public static final String TABLE_PLAYLIST = "playlist";public static final String COLUMN_ID = "_id";public static final String COLUMN_NAME = "name";private static final String DATABASE_CREATE = "create table " + TABLE_PLAYLIST + "(" + COLUMN_ID + " integer primary key autoincrement, " + COLUMN_NAME + " text not null);";public DatabaseHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}@Overridepublic void onCreate(SQLiteDatabase database) {database.execSQL(DATABASE_CREATE);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("DROP TABLE IF EXISTS " + TABLE_PLAYLIST);onCreate(db);}
}
2. ContentProvider 实现
public class PlaylistProvider extends ContentProvider {private static final String AUTHORITY = "com.example.musicplayer.provider";private static final String BASE_PATH = "playlists";public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);private static final int PLAYLISTS = 1;private static final int PLAYLIST_ID = 2;private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);static {uriMatcher.addURI(AUTHORITY, BASE_PATH, PLAYLISTS);uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", PLAYLIST_ID);}private SQLiteDatabase database;@Overridepublic boolean onCreate() {DatabaseHelper dbHelper = new DatabaseHelper(getContext());database = dbHelper.getWritableDatabase();return true;}@Nullable@Overridepublic Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,@Nullable String[] selectionArgs, @Nullable String sortOrder) {switch (uriMatcher.match(uri)) {case PLAYLISTS:return database.query(DatabaseHelper.TABLE_PLAYLIST, projection, selection, selectionArgs, null, null, sortOrder);case PLAYLIST_ID:selection = DatabaseHelper.COLUMN_ID + "=?";selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};return database.query(DatabaseHelper.TABLE_PLAYLIST, projection, selection, selectionArgs, null, null, sortOrder);default:throw new IllegalArgumentException("Unknown URI: " + uri);}}@Nullable@Overridepublic Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {long id = database.insert(DatabaseHelper.TABLE_PLAYLIST, null, values);getContext().getContentResolver().notifyChange(uri, null);return ContentUris.withAppendedId(CONTENT_URI, id);}@Overridepublic int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {int rowsDeleted;switch (uriMatcher.match(uri)) {case PLAYLISTS:rowsDeleted = database.delete(DatabaseHelper.TABLE_PLAYLIST, selection, selectionArgs);break;case PLAYLIST_ID:selection = DatabaseHelper.COLUMN_ID + "=?";selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};rowsDeleted = database.delete(DatabaseHelper.TABLE_PLAYLIST, selection, selectionArgs);break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}getContext().getContentResolver().notifyChange(uri, null);return rowsDeleted;}@Overridepublic int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {int rowsUpdated;switch (uriMatcher.match(uri)) {case PLAYLISTS:rowsUpdated = database.update(DatabaseHelper.TABLE_PLAYLIST, values, selection, selectionArgs);break;case PLAYLIST_ID:selection = DatabaseHelper.COLUMN_ID + "=?";selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};rowsUpdated = database.update(DatabaseHelper.TABLE_PLAYLIST, values, selection, selectionArgs);break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}getContext().getContentResolver().notifyChange(uri, null);return rowsUpdated;}@Nullable@Overridepublic String getType(@NonNull Uri uri) {switch (uriMatcher.match(uri)) {case PLAYLISTS:return "vnd.android.cursor.dir/vnd.com.example.musicplayer.provider.playlists";case PLAYLIST_ID:return "vnd.android.cursor.item/vnd.com.example.musicplayer.provider.playlists";default:throw new IllegalArgumentException("Unknown URI: " + uri);}}
}

3. 总结

通过以上示例,我们展示了 ContentProvider 在跨应用数据共享、动态授权、数据观察和通知等方面的高级应用。通过合理设计 URI 结构、权限管理和数据缓存,可以有效提升 ContentProvider 的性能和安全性。在实际开发中,结合具体需求和场景,灵活运用这些高级技巧和最佳实践,是开发高效、可靠 Android 应用的关键。理解和掌握 ContentProvider 的高级使用方法,可以让开发者在数据管理和共享方面得心应手。

欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

操作系统中存储系统简介 虚拟内存、内存管理、分页、保护

文章目录 存储器的层次结构存储器之间的实际价格和性能差距存储器的层次关系 虚拟内存简述主要概念虚拟内存的优势 内存管理内存碎片 内存分页页面置换算法TLB加速分页软件TLB管理针对大内存的页管理技术三个重要的缓存能力 内存保护总结 存储器的层次结构 对于存储器&#xff…

用Python打造精彩动画与视频.2.1 Python基础语法概述

2.1 Python基础语法概述 Python作为一门功能强大且易于学习的编程语言&#xff0c;其基础语法简单直观&#xff0c;非常适合初学者入门。这一节将带你了解Python的基本语法规则&#xff0c;为后续制作动画和视频打下坚实的基础。 1. 变量与数据类型 Python的变量不需要提前声…

OCC 创建倒角

目录 一、简介 二、示例 1、使用BRepFilletAPI_MakeFillet 创建倒角 2、使用BRepFilletAPI_MakeChamfer创建斜面倒角 三、总结 一、简介 倒角指的是把工件的棱角切削成一定斜面的加工。倒角是为了去除零件上因机加工产生的毛刺,也为了便于零件装配,一般在零件端部做出…

达梦数据库归档介绍

一、什么是归档 数据库归档是一种数据管理策略&#xff0c;它涉及将旧的、不经常访问的数据移动到一个单独的存储设备&#xff0c;以便在需要时可以检索&#xff0c;同时保持数据库的性能和效率。 归档的主要目标是为了释放数据库中的空间&#xff0c;以便更有效地利用高性能…

【C++高阶数据结构】红黑树:全面剖析与深度学习

目录 &#x1f680; 前言&#xff1a;红黑树与AVL树的比较一&#xff1a; &#x1f525; 红黑树的概念二&#xff1a; &#x1f525; 红黑树的性质 三&#xff1a; &#x1f525; 红黑树节点的定义和结构&#x1f680; 3.1 基本元素&#x1f680; 3.2 节点颜色&#x1f680; 3.…

MongoDB聚合操作详解

文章目录 聚合操作聚合管道管道&#xff08;Pipeline&#xff09;和阶段&#xff08;Stage&#xff09;常用的聚合阶段运算符准备数据集&#xff0c;执行脚本$project$match$count$group$unwind$limit$skip$sort$lookup聚合操作案例1聚合操作案例2 聚合优化执行顺序内存排序 整…

Hugo部署到Vercel踩大坑——全是XML文件?

问题描述 部署到Vercel全都是XML文件 Vercel是著名PAAS服务&#xff0c;相比于 Github Pages&#xff0c;其中国大陆可直接访问&#xff0c;因此尝试把Hugo站点发布到vercel中&#xff0c;部署后遇到问题&#xff0c;所有页面都为xml文件&#xff0c;如下所示&#xff1a; Ve…

AIGC-VDM -Video Diffusion Models论文解读

homepage&#xff1a;https://video-diffusion.github.io/ paper:https://arxiv.org/pdf/2204.03458 参考:https://zhuanlan.zhihu.com/p/585009571 视频生成方面的扩散模型 论文Video Diffusion Models精读&#xff0c;笔者会多多更新AIGC相关知识&#xff01;点个关注吧&…

SpringCloud Alibaba 微服务(二):Nacos

目录 前言 一、什么是Nacos&#xff1f; 二、Nacos的主要功能 服务发现与注册 配置管理 服务健康监控 集群模式 三、安装Nacos 下载Nacos 初始化Nacos 单机模式 集群模式 访问Nacos 四、服务注册 新建子工程 引入Nacos依赖 配置application.yml 创建启动类 …

内网穿透的应用-中文版个人知识库Trilium笔记本地安装结合内网穿透远程协作

文章目录 前言1. 安装docker与docker-compose2. 启动容器运行镜像3. 本地访问测试4.安装内网穿透5. 创建公网地址6. 创建固定公网地址 前言 今天和大家分享一款在G站获得了26K的强大的开源在线协作笔记软件&#xff0c;Trilium Notes的中文版如何在Linux环境使用docker本地部署…

Linux基础复习(五)

前言 本文介绍了Linux常用命令&#xff0c;接Linux基础复习&#xff08;四&#xff09; 一、常用命令 命令通配符 在Linux中&#xff0c;命令通配符&#xff08;也称为通配符模式或通配符表达式&#xff09;是用来匹配文件名或其他字符串的一种特殊字符。这些通配符可以帮助…

深入解析 GZIP 压缩传输:优化网络性能的利器

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119@qq.com] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? 专栏导…

访问控制列表(ACL)

文章目录 ACL原理与基本配置ACL分类ACL组成ACL规则的匹配与应用 ACL原理与基本配置 ACL(Access Control List&#xff0c;访问控制列表) 读取二层、三层、四层报文信息根据预先定义好的规则对报文进行过滤和分类实现网络访问控制、防止网络攻击和提高网络带宽利用率等目的提高…

力扣SQL50 上级经理已离职的公司员工 一题双解

Problem: 1978. 上级经理已离职的公司员工 Code -- 方法 1 -- select e1.employee_id -- from employees e1 -- left join employees e2 -- on e1.manager_id e2.employee_id -- where e1.salary < 30000 -- and e1.manager_id is not null -- and e2.employee_id is…

学鸿蒙开发好找工作吗?

学鸿蒙开发是一个非常有潜力的方向&#xff0c;因为鸿蒙系统是华为自主研发的操作系统&#xff0c;随着其在全球范围内的推广和应用&#xff0c;越来越多的企业和组织开始重视并采用这一系统。这使得鸿蒙开发者的市场需求正在持续增长&#xff0c;为鸿蒙开发者提供了更多的就业…

C# 设计倒计时器、串口助手开发

文章目录 1. 实现一个简单的倒计时器开始、暂停2. 串口助手开发 1. 实现一个简单的倒计时器开始、暂停 namespace Timer {public partial class Form1 : Form{int count;//用于定时器计数int time;//存储设定的定时值bool parse false;//控制暂停计时public Form1(){Initiali…

Qt Designer,仿作一个ui界面的练习(一):界面的基本布局

初学不要太复杂&#xff0c;先做一个结构简单的&#xff0c;大致规划一下功能分区&#xff0c;绘制草图&#xff1a; 最终的效果&#xff1a; 界面主要由顶边栏、侧边栏、内容区构成。顶边栏左边是logo&#xff0c;右边是时钟显示。侧边栏最上边是切换按钮&#xff0c;用以动画…

Qt中对象树机制的优点以及潜在的隐患

目录 一、什么是对象树 二、对象树的优点 三、对象树潜在的隐患 一、什么是对象树 Qt中的 QObject 会用对象树来组织管理自己&#xff0c;那什么是对象树? 这个概念非常好理解。因为 QObject 类就有一个私有变量 QList<QObject *>&#xff0c;专门存储这个类的子孙后…

centos7-8/redhat7-8一键安装配置vsftp服务

1.脚本介绍 1.1.介绍&#xff1a; linux下一键安装及配置vsftpd服务 &#xff0c;通过执行install.sh脚本&#xff0c;脚本会根据参数区域的值执行安装和配置vsftp服务&#xff0c;安装后会创建一个默认ftp用户wangxf密码wangxf2023 1、支持自定义安装(更改脚本内参数值) 2、…

一篇文章带你入门爬虫并编写自己的第一个爬虫程序

一、引言 目前我们处在一个信息快速迭代更新的时代&#xff0c;海量的数据以大爆炸的形式出现在网络之中&#xff0c;相比起过去那个通过广播无线电、书籍报刊等传统媒介获取信息的方式&#xff0c;我们现在通过网络使用搜索引擎几乎可以获得任何我们需要的信息资源。 但与此同…