深入分析 Android ContentProvider (一)
创始人
2024-11-03 21:37:19
0

文章目录

    • 深入分析 Android ContentProvider (一)
    • 1. Android 中的 ContentProvider 设计说明
      • 1.1. ContentProvider 的设计初衷
      • 1.2. ContentProvider 的基本结构
      • 1.3. ContentProvider 的实现
        • 示例:实现一个简单的 ContentProvider
      • 1.4. ContentProvider 的使用
    • 2. ContentProvider 的设计优势
    • 3. ContentProvider 的注意事项
    • 4. 总结

深入分析 Android ContentProvider (一)

1. Android 中的 ContentProvider 设计说明

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

1.1. ContentProvider 的设计初衷

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

1.2. ContentProvider 的基本结构

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

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

1.3. ContentProvider 的实现

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

示例:实现一个简单的 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);     }      @Override     public void onCreate(SQLiteDatabase db) {         db.execSQL(TABLE_CREATE);     }      @Override     public 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);     }      @Override     public boolean onCreate() {         DatabaseHelper helper = new DatabaseHelper(getContext());         database = helper.getWritableDatabase();         return true;     }      @Nullable     @Override     public 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     @Override     public 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     @Override     public 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);     }      @Override     public 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;     }      @Override     public 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
 

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); 

2. ContentProvider 的设计优势

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

3. ContentProvider 的注意事项

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

4. 总结

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

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

在这里插入图片描述

相关内容

热门资讯

最终!微乐家乡麻辣自建房辅助a... 最终!微乐家乡麻辣自建房辅助app,哥哥打大a有没有辅助,介绍教程(都是真的是有挂)-哔哩哔哩1、微...
受玩家影响!广东雀神祈福真的有... 受玩家影响!广东雀神祈福真的有用吗,南宁友乐辅助,攻略教程(都是存在有挂)-哔哩哔哩1、该软件可以轻...
此事引发网友热议!闽乐乐510... 此事引发网友热议!闽乐乐510k脚本,多乐辅助app,黑科技教程(原来是真的挂)-哔哩哔哩1、下载好...
不少玩家反映!微乐老友广东辅助... 不少玩家反映!微乐老友广东辅助器,逗好乐游辅助器,德州教程(总是有挂)-哔哩哔哩1、微乐老友广东辅助...
出乎意料的是!福麻圈辅助,丰城... 出乎意料的是!福麻圈辅助,丰城呱呱辅助器,透明挂教程(真是真的是有挂)-哔哩哔哩暗藏猫腻,小编详细说...
网友热议!腾达填大坑辅助器,微... 网友热议!腾达填大坑辅助器,微信小程序微乐房间怎么开挂,德州论坛(果然存在有挂)-哔哩哔哩该软件可以...
于此同时!决战卡五星辅助ios... 于此同时!决战卡五星辅助ios,家乡大二辅助,玩家教你(真是存在有挂)-哔哩哔哩一、决战卡五星辅助i...
目前!广东闲来辅助,广西友乐免... 目前!广东闲来辅助,广西友乐免费辅助,黑科技教程(果然有挂)-哔哩哔哩1)广西友乐免费辅助辅助挂:进...
据报道!微信微乐游戏辅助脚本,... 据报道!微信微乐游戏辅助脚本,悟空大厅怎么挂辅助,力荐教程(好像是真的挂)-哔哩哔哩1、不需要AI权...
随着!创思维激K辅助器开挂,天... 随着!创思维激K辅助器开挂,天天微友有辅助吗,教你攻略(其实真的是有挂)-哔哩哔哩1、用户打开应用后...