深入分析 Android ContentProvider (十一)

文章目录

    • [深入分析 Android ContentProvider (十一)](#深入分析 Android ContentProvider (十一))
    • [ContentProvider 的系统代码分析](#ContentProvider 的系统代码分析)
      • [1. ContentProvider 的核心类](#1. ContentProvider 的核心类)
      • [2. ContentProvider 的工作流程](#2. ContentProvider 的工作流程)
      • [3. 详细示例分析](#3. 详细示例分析)
        • [3.1 数据库和 ContentProvider 的初始化](#3.1 数据库和 ContentProvider 的初始化)
        • [3.2 查询操作](#3.2 查询操作)
        • [3.3 数据更新通知](#3.3 数据更新通知)
      • [4. 总结](#4. 总结)

深入分析 Android ContentProvider (十一)

ContentProvider 的系统代码分析

为了更深入地了解 Android 中 ContentProvider 的工作原理,我们需要查看其底层实现和运行机制。以下是对 ContentProvider 在 Android 系统代码中的详细分析。

1. ContentProvider 的核心类

ContentProvider 的核心类主要包括:

  1. ContentProvider
  2. ContentResolver
  3. UriMatcher

我们将逐个分析这些类的关键部分和工作原理。

1.1. ContentProvider

ContentProvider 是一个抽象类,开发者需要继承它并实现核心的 CRUD 操作。以下是 ContentProvider 的一些关键方法和流程:

java 复制代码
public abstract class ContentProvider {
    private Transport mTransport = new Transport();

    /**
     * Called when the provider is being started.
     */
    public abstract boolean onCreate();

    /**
     * Implement this to handle query requests from clients.
     */
    public abstract Cursor query(Uri uri, String[] projection, String selection,
                                 String[] selectionArgs, String sortOrder);

    /**
     * Implement this to handle requests for the MIME type of the data at the given URI.
     */
    public abstract String getType(Uri uri);

    /**
     * Implement this to handle requests to insert a new row.
     */
    public abstract Uri insert(Uri uri, ContentValues values);

    /**
     * Implement this to handle requests to delete one or more rows.
     */
    public abstract int delete(Uri uri, String selection, String[] selectionArgs);

    /**
     * Implement this to handle requests to update one or more rows.
     */
    public abstract int update(Uri uri, ContentValues values, String selection,
                               String[] selectionArgs);

    /**
     * This is called when a client starts a query.
     */
    public final Cursor query(Uri uri, String[] projection, String selection,
                              String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
        return query(uri, projection, selection, selectionArgs, sortOrder);
    }

    // ... other methods and inner classes ...
}
核心方法分析:
  • onCreate(): 当 ContentProvider 被创建时调用,通常用于初始化操作。
  • query(): 处理查询请求,返回 Cursor 对象。
  • getType(): 返回给定 URI 的 MIME 类型。
  • insert(): 处理插入请求,返回新插入行的 URI。
  • delete(): 处理删除请求,返回删除的行数。
  • update(): 处理更新请求,返回更新的行数。

这些方法定义了 ContentProvider 的基本操作接口,具体的实现由开发者提供。

1.2. ContentResolver

ContentResolver 是用于与 ContentProvider 交互的客户端接口。通过 ContentResolver,应用可以查询、插入、更新和删除数据。

java 复制代码
public abstract class ContentResolver {
    // ... other methods ...

    public final Cursor query(final Uri uri, String[] projection, String selection,
                              String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
        IContentProvider provider = acquireProvider(uri);
        if (provider == null) {
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        try {
            return provider.query(mPackageName, uri, projection, selection, selectionArgs, sortOrder, cancellationSignal);
        } catch (RemoteException e) {
            throw new RuntimeException("Failed to query: " + uri, e);
        } finally {
            releaseProvider(provider);
        }
    }

    // ... other methods ...
}
核心方法分析:
  • query(): 通过 IContentProvider 接口与 ContentProvider 通信,执行查询操作。
  • acquireProvider(): 获取指定 URI 的 ContentProvider。
  • releaseProvider(): 释放 ContentProvider 的引用。
1.3. UriMatcher

UriMatcher 用于匹配和解析 URI。在 ContentProvider 中,常常使用 UriMatcher 来区分不同的 URI 请求。

java 复制代码
public class UriMatcher {
    private static final int NO_MATCH = -1;
    private HashMap<String, Object> mValues;

    public UriMatcher(int code) {
        mCode = code;
        mValues = new HashMap<>();
    }

    public void addURI(String authority, String path, int code) {
        if (code < 0) {
            throw new IllegalArgumentException("code " + code + " is invalid: it must be positive");
        }
        mValues.put(makeKey(authority, path), code);
    }

    public int match(Uri uri) {
        String key = makeKey(uri.getAuthority(), uri.getPath());
        Integer code = (Integer) mValues.get(key);
        return code != null ? code : NO_MATCH;
    }

    private String makeKey(String authority, String path) {
        return authority + "/" + path;
    }
}
核心方法分析:
  • addURI(): 添加 URI 和对应的 code。
  • match(): 匹配给定 URI,返回对应的 code。

2. ContentProvider 的工作流程

  1. 初始化 :当应用启动时,ContentProvider 会通过 onCreate() 方法进行初始化。这个方法通常用于数据库的初始化或其他资源的准备工作。

  2. 请求处理 :当应用通过 ContentResolver 发起数据请求时,系统会通过 IContentProvider 接口调用 ContentProvider 的对应方法(如 query()insert()update()delete())。这些方法会在后台线程中执行,以避免阻塞主线程。

  3. URI 匹配 :ContentProvider 使用 UriMatcher 来解析和匹配请求 URI。根据匹配结果,执行不同的操作逻辑。

  4. 数据操作 :执行数据库操作(如查询、插入、更新、删除)。这些操作通常使用 SQLiteDatabase 进行。

  5. 结果返回 :操作完成后,返回结果给调用方。对于查询操作,会返回一个 Cursor 对象;对于插入操作,会返回新记录的 URI;对于更新和删除操作,会返回影响的行数。

  6. 通知变化 :数据发生变化时,通过 ContentResolver.notifyChange() 通知观察者,触发数据刷新。

3. 详细示例分析

假设我们有一个 ContentProvider,用于管理音乐播放列表。我们将从系统代码的角度分析其工作流程。

3.1 数据库和 ContentProvider 的初始化
java 复制代码
public class PlaylistProvider extends ContentProvider {
    private static final String AUTHORITY = "com.example.musicprovider";
    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;

    @Override
    public boolean onCreate() {
        DatabaseHelper helper = new DatabaseHelper(getContext());
        database = helper.getWritableDatabase();
        return true;
    }

    // ... other methods ...
}
3.2 查询操作
java 复制代码
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                    @Nullable String[] selectionArgs, @Nullable String sortOrder) {
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
    queryBuilder.setTables(DatabaseHelper.TABLE_PLAYLIST);

    switch (uriMatcher.match(uri)) {
        case PLAYLISTS:
            break;
        case PLAYLIST_ID:
            queryBuilder.appendWhere(DatabaseHelper.COLUMN_ID + "=" + uri.getLastPathSegment());
            break;
        default:
            throw new IllegalArgumentException("Unknown URI: " + uri);
    }

    Cursor cursor = queryBuilder.query(database, projection, selection, selectionArgs, null, null, sortOrder);
    cursor.setNotificationUri(getContext().getContentResolver(), uri);
    return cursor;
}
3.3 数据更新通知
java 复制代码
@Override
public 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;
}

在这个示例中,ContentProvider 会在数据更新后通过 notifyChange() 方法通知数据变化,触发观察者(如 CursorLoader)重新加载数据。

4. 总结

通过对 ContentProvider 系统代码的分析,我们可以深入理解其工作原理和机制。ContentProvider 提供了一个标准接口,用于跨应用的数据共享和管理。通过 ContentResolver,应用可以方便地与 ContentProvider 进行交互,而 UriMatcher 则简化了 URI 的解析和匹配。掌握这些底层实现和工作流程,可以帮助开发者更好地设计和优化 ContentProvider,在实际项目中实现高效、安全的数据操作。

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

相关推荐
小蜜蜂嗡嗡35 分钟前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0041 分钟前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil2 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你2 小时前
Android View的绘制原理详解
android
移动开发者1号5 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号5 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best10 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk10 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭15 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin
aqi0016 小时前
FFmpeg开发笔记(七十七)Android的开源音视频剪辑框架RxFFmpeg
android·ffmpeg·音视频·流媒体