深入分析 Android ContentProvider (一)

news/2024/10/18 18:28:37/

文章目录

ContentProvider__1">深入分析 Android ContentProvider (一)

ContentProvider__2">1. Android 中的 ContentProvider 设计说明

ContentProvider 是 Android 中四大组件之一,主要用于在不同应用之间共享数据。ContentProvider 提供了一个一致的接口,使得应用能够以一种受控和安全的方式访问和修改存储的数据。通过 ContentProvider,数据可以被跨进程共享,而不必将数据直接暴露给其他应用。

ContentProvider__5">1.1. ContentProvider 的设计初衷

  1. 数据共享:在 Android 中,应用之间的直接数据访问是不允许的。ContentProvider 提供了一种标准化的方式,使得应用可以安全地共享数据。
  2. 数据封装:通过 ContentProvider,数据存取逻辑可以封装在一个单独的组件中,其他组件只需通过 ContentProvider 提供的接口进行数据操作。
  3. 统一接口ContentProvider 提供了一个统一的接口,支持多种数据存取方式(如插入、删除、更新、查询),并且支持对数据进行事务操作。

ContentProvider__11">1.2. ContentProvider 的基本结构

一个典型的 ContentProvider 包括以下几个部分:

  1. URI:统一资源标识符,用于定位 ContentProvider 中的数据。
  2. MIME 类型:用于标识返回的数据类型。
  3. 数据存储:实际存储数据的地方,如数据库、文件等。
  4. 数据操作方法:用于操作数据的标准方法,如 queryinsertupdatedelete

ContentProvider__19">1.3. ContentProvider 的实现

要实现一个 ContentProvider,需要继承 ContentProvider 类并实现其抽象方法。以下是一个简单的示例:

ContentProvider_23">示例:实现一个简单的 ContentProvider
  1. 创建数据库和表

首先,需要创建一个 SQLite 数据库来存储数据。

public class DatabaseHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "example.db";private static final int DATABASE_VERSION = 1;public static final String TABLE_NAME = "example";public static final String COLUMN_ID = "_id";public static final String COLUMN_NAME = "name";private static final String TABLE_CREATE ="CREATE TABLE " + TABLE_NAME + " (" +COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +COLUMN_NAME + " TEXT);";public DatabaseHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL(TABLE_CREATE);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);onCreate(db);}
}
  1. 实现 ContentProvider

实现 ContentProvider 类并覆盖其方法。

public class ExampleProvider extends ContentProvider {private static final String AUTHORITY = "com.example.provider";private static final String BASE_PATH = "example";public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);private SQLiteDatabase database;private static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.example.example";private static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.example.example";private static final int EXAMPLES = 1;private static final int EXAMPLE_ID = 2;private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);static {uriMatcher.addURI(AUTHORITY, BASE_PATH, EXAMPLES);uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", EXAMPLE_ID);}@Overridepublic boolean onCreate() {DatabaseHelper helper = new DatabaseHelper(getContext());database = helper.getWritableDatabase();return true;}@Nullable@Overridepublic Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,@Nullable String[] selectionArgs, @Nullable String sortOrder) {Cursor cursor;switch (uriMatcher.match(uri)) {case EXAMPLES:cursor = database.query(DatabaseHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);break;case EXAMPLE_ID:cursor = database.query(DatabaseHelper.TABLE_NAME, projection, DatabaseHelper.COLUMN_ID + "=?",new String[]{String.valueOf(ContentUris.parseId(uri))}, null, null, sortOrder);break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}cursor.setNotificationUri(getContext().getContentResolver(), uri);return cursor;}@Nullable@Overridepublic String getType(@NonNull Uri uri) {switch (uriMatcher.match(uri)) {case EXAMPLES:return CONTENT_TYPE;case EXAMPLE_ID:return CONTENT_ITEM_TYPE;default:throw new IllegalArgumentException("Unknown URI: " + uri);}}@Nullable@Overridepublic Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {long id = database.insert(DatabaseHelper.TABLE_NAME, null, values);if (id > 0) {Uri returnUri = ContentUris.withAppendedId(CONTENT_URI, id);getContext().getContentResolver().notifyChange(returnUri, null);return returnUri;}throw new SQLException("Failed to insert row into " + uri);}@Overridepublic int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {int rowsDeleted;switch (uriMatcher.match(uri)) {case EXAMPLES:rowsDeleted = database.delete(DatabaseHelper.TABLE_NAME, selection, selectionArgs);break;case EXAMPLE_ID:rowsDeleted = database.delete(DatabaseHelper.TABLE_NAME, DatabaseHelper.COLUMN_ID + "=?",new String[]{String.valueOf(ContentUris.parseId(uri))});break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}if (rowsDeleted > 0) {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 EXAMPLES:rowsUpdated = database.update(DatabaseHelper.TABLE_NAME, values, selection, selectionArgs);break;case EXAMPLE_ID:rowsUpdated = database.update(DatabaseHelper.TABLE_NAME, values, DatabaseHelper.COLUMN_ID + "=?",new String[]{String.valueOf(ContentUris.parseId(uri))});break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}if (rowsUpdated > 0) {getContext().getContentResolver().notifyChange(uri, null);}return rowsUpdated;}
}
  1. 在 Manifest 中声明 ContentProvider
<providerandroid:name=".ExampleProvider"android:authorities="com.example.provider"android:exported="true" />

ContentProvider__187">1.4. ContentProvider 的使用

  1. 查询数据
Uri uri = Uri.parse("content://com.example.provider/example");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null) {while (cursor.moveToNext()) {String name = cursor.getString(cursor.getColumnIndexOrThrow("name"));// 处理数据}cursor.close();
}
  1. 插入数据
ContentValues values = new ContentValues();
values.put("name", "Example Name");
Uri uri = Uri.parse("content://com.example.provider/example");
Uri newUri = getContentResolver().insert(uri, values);
  1. 更新数据
ContentValues values = new ContentValues();
values.put("name", "Updated Name");
Uri uri = Uri.parse("content://com.example.provider/example/1");
int rowsUpdated = getContentResolver().update(uri, values, null, null);
  1. 删除数据
Uri uri = Uri.parse("content://com.example.provider/example/1");
int rowsDeleted = getContentResolver().delete(uri, null, null);

ContentProvider__228">2. ContentProvider 的设计优势

  1. 数据共享:提供了标准化的数据共享接口,使得不同应用可以安全地共享数据。
  2. 数据封装:将数据存取逻辑封装在 ContentProvider 中,降低了模块间的耦合度。
  3. 统一访问:通过统一的 URI 和接口访问数据,简化了数据操作。
  4. 跨进程通信:支持跨进程访问数据,使得应用之间可以实现复杂的数据交互。

ContentProvider__235">3. ContentProvider 的注意事项

  1. 性能考虑:由于 ContentProvider 通常用于跨进程数据共享,频繁的跨进程调用会有性能开销,需注意优化查询和数据操作。
  2. 权限管理:确保数据访问权限的安全性,通过权限声明和检查,防止数据泄露和未经授权的访问。
  3. 数据一致性:确保在高并发场景下的数据一致性,必要时使用事务机制。

4. 总结

ContentProvider 是 Android 中用于数据共享和跨进程通信的重要组件,通过统一的接口和标准化的 URI 访问方式,提供了安全、封装和

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

在这里插入图片描述


http://www.ppmy.cn/news/1505905.html

相关文章

CSP初赛知识点讲解(四)

CSP初赛知识点讲解&#xff08;四&#xff09; 位运算与运算(&)或运算(|)异或运算(^)取反运算(~)左移运算右移运算 存储空间时间计算例题训练&#xff08;六&#xff09; 位运算 所有的数据在计算机中都是以二进制的方式存储&#xff0c;为了方便计算&#xff0c;提供了一…

使用Redis来实现JWT令牌主动失效机制

目录 一.实现思路&#xff1a; 二.实现代码解析&#xff1a; 1.首先配置Redis的相关配置文件&#xff1a; &#xff08;1&#xff09;pom.xml&#xff1a; &#xff08;2&#xff09;在application.yml中配置相关信息&#xff1a; &#xff08;3&#xff09;编写配置类&a…

Hooks是干什么的?

在编程的世界里&#xff0c;“Hooks”是一个你可能会经常听到的术语&#xff0c;特别是在前端开发中。它们为开发者提供了一种优雅且高效的方式来扩展和控制代码的执行流程。本文将深入浅出地介绍Hooks是什么&#xff0c;它们的作用是什么&#xff0c;以及如何在代码中使用它们…

uniapp实现可视化图表(轻量、内存小)

图表官网&#xff1a;uCharts官网 - 秋云uCharts跨平台图表库 用原生组件&#xff1a; 选择自己需要的模块&#xff0c;以小程序为例&#xff1a; 把min.js下载下来 把min.js放到小程序代码中&#xff0c;引用即可&#xff0c;使用案例看官网&#xff0c; 在官网中选择想要的…

Linux 为何不把图形用户界面写入内核?

Linux 为何不把图形用户界面写入内核&#xff1f; 早先是没能力&#xff0c;之后是没必要&#xff0c;现在是不应该 先插一句&#xff0c;现代Windows9的图形也不在内核里&#xff0c;只是还保留一组兼容。 90年代时的计算机都是两套图形系统:一套是普通软件窗口API9&#xff…

在 Qt 中实现 GIF 动画显示

在 Qt 图形界面编程中&#xff0c;有时我们需要在应用窗口中显示 GIF 动画。要实现这一点&#xff0c;我们可以利用 QGraphicsView 和 QGraphicsScene 类来显示普通图片&#xff0c;同时也可以轻松地扩展以显示 GIF 动画。本文将介绍如何在 Qt 中实现这一功能。 问题描述 一位…

TCP协议程序设计

文章目录 前言一、TCP协议程序是什么&#xff1f;二、使用步骤 1.服务器端与客户端2.实操展示总结 前言 TCP网络程序设计是指利用Socket类编写通信程序。利用TCP协议进行通讯的两个应用程序是有主次之分的&#xff0c;一个称为服务器程序&#xff0c;另一个称为客户机程序&…

RabbitMQ之基于注解声明队列交换机:使用@RabbitListener实现消息监听

文章目录 什么是RabbitListener&#xff1f;队列和交换机的基本概念使用RabbitListener注解声明队列和交换机代码解析1. QueueBinding2. 消费者方法 运行原理应用场景总结 在现代的微服务架构中&#xff0c;消息队列是一种重要的异步通信机制。RabbitMQ作为一种流行的消息代理软…