首页 > 其他分享 >深入分析 Android ContentProvider (一)

深入分析 Android ContentProvider (一)

时间:2024-07-21 16:26:25浏览次数:14  
标签:null String Uri uri 深入分析 Android ContentProvider example

文章目录

深入分析 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
<provider
    android:name=".ExampleProvider"
    android:authorities="com.example.provider"
    android:exported="true" />

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 访问方式,提供了安全、封装和

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

在这里插入图片描述

标签:null,String,Uri,uri,深入分析,Android,ContentProvider,example
From: https://blog.csdn.net/rjdeng/article/details/139654189

相关文章

  • 车载 Android 核心服务 - CarService 解析
    前言在之前的文章从应用工程师的角度再谈车载Android系统中提到了"CarService是车载Android系统的核心服务之一,所有应用都需要通过CarService来查询、控制整车的状态",不仅仅是车辆控制,实际上CarService几乎就是整个车载Framework最核心的组件,这也让CarService成了各种bug的......
  • Android中Activity生命周期详解
    目录一典型情况二异常情况2.1系统配置改变2.2系统资源不足kill掉低优先级activityActivity是四大组件之一,也是接触的最多的,一般来说Activity经常是与用户交互的界面。一典型情况先看下google官网,其实已经很清楚了再来个总结onCreate,正在被创建,一次,可以做......
  • Android中Retrofit的学习和使用记录
    目录一概述二优点三代码3.1Api3.2RetrofitManager3.3DataRepository3.4在ViewModel中请求3.4最后在ui里面调用一概述是Android一个restful风格的网络请求框架,本质上还是OkHttp进行请求,Retrofit负责对接口的封装。Retrofit接口层封装请求参数、Header、U......
  • Android Studio项目中的重复类、动态版本控制及其他优化方法
    本文介绍在Android开发过程中,我们常常会遇到一些棘手的问题,如重复类冲突、动态版本控制及依赖打包等。本文将介绍如何解决这些问题,并提供一些有用的优化方法。1.解决重复类冲突问题在引入多个JAR包或AAR包时,可能会遇到类重复的问题,导致编译失败。这里提供了两种解决方......
  • 深入分析:std::lock_guard 的使用及其最佳实践
    ......
  • SQLite数据库在Android中的使用
    目录一,SQLite简介二,SQLIte在Android中的使用1,打开或者创建数据库2,创建表3,插入数据4,删除数据5,修改数据 6,查询数据三,SQLiteOpenHelper类四,SQLite中事务的处理一,SQLite简介        SQLite是一个无服务器的,零配置的,事务性的SQL数据库引擎。无服务器,意味着使......
  • Android10.0 锁屏分析-KeyguardPatternView图案锁分析
    首先一起看看下面这张图:通过前面锁屏加载流程可以知道在KeyguardSecurityContainer中使用getSecurityView()根据不同的securityModeinflate出来,并添加到界面上的。我们知道,Pattern锁所使用的layout是R.layout.keyguard_pattern_view;<com.android.keyguard.KeyguardPat......
  • 如何在Android Java中访问android/data/文件夹(应用程序包)?
    **我的应用程序的包名称是com.gorlopsen。该应用程序必须上传了没有它就无法工作的文件。文件下载到存档中并解压到android/data/com.gorlopsen文件夹中。但是,在解压阶段,出现下载错误,导致应用程序无法使用。在网上找到了有关访问所有文件的信息,但并不适合我。是否可以请求......
  • 基于Android平台开发,在线电影购票系统(九)用户评论列表实现
    1.涉及到的技术点使用SQLite数据库实现用户评论数据保存使用RecyclerView+adapter实现用户评论列表2.具体代码实现过程CommentListAdapter.java适配器publicclassCommentListAdapterextendsRecyclerView.Adapter<CommentListAdapter.MyHolder>{privateList......
  • Android C++系列:Linux文件系统(二)
    1.VFS虚拟文件系统Linux支持各种各样的文件系统格式,如ext2、ext3、reiserfs、FAT、NTFS、iso9660等等,不同的磁盘分区、光盘或其它存储设备都有不同的文件系统格式,然而这些文件系统都可以mount到某个目录下,使我们看到一个统一的目录树,各种文件系统上的目录和文件我们用l......