深入分析 Android ContentProvider (一)

文章目录

    • [深入分析 Android ContentProvider (一)](#深入分析 Android ContentProvider (一))
    • [1. Android 中的 ContentProvider 设计说明](#1. Android 中的 ContentProvider 设计说明)
      • [1.1. ContentProvider 的设计初衷](#1.1. ContentProvider 的设计初衷)
      • [1.2. ContentProvider 的基本结构](#1.2. ContentProvider 的基本结构)
      • [1.3. ContentProvider 的实现](#1.3. ContentProvider 的实现)
        • [示例:实现一个简单的 ContentProvider](#示例:实现一个简单的 ContentProvider)
      • [1.4. ContentProvider 的使用](#1.4. ContentProvider 的使用)
    • [2. ContentProvider 的设计优势](#2. ContentProvider 的设计优势)
    • [3. ContentProvider 的注意事项](#3. ContentProvider 的注意事项)
    • [4. 总结](#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 数据库来存储数据。

java 复制代码
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 类并覆盖其方法。

java 复制代码
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
xml 复制代码
<provider
    android:name=".ExampleProvider"
    android:authorities="com.example.provider"
    android:exported="true" />

1.4. ContentProvider 的使用

  1. 查询数据
java 复制代码
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. 插入数据
java 复制代码
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. 更新数据
java 复制代码
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. 删除数据
java 复制代码
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 访问方式,提供了安全、封装和

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

相关推荐
雨白4 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹5 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空7 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭7 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日8 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安8 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑9 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟13 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡14 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0014 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体