深入分析 Android ContentProvider (八)

深入分析 Android ContentProvider (八)

ContentProvider 高级使用及最佳实践案例分析(续)

1. 深入了解跨应用数据共享

跨应用数据共享是 ContentProvider 的一个重要功能,它允许应用之间安全地共享数据。为此,我们需要定义清晰的权限和 URI 结构,以确保数据在不同应用之间安全传输。

示例:跨应用数据共享的完整实现
1. 定义权限

AndroidManifest.xml 中定义权限:

<permission
    android:name="com.example.myapp.READ_DATA"
    android:protectionLevel="signature" />
<permission
    android:name="com.example.myapp.WRITE_DATA"
    android:protectionLevel="signature" />
2. 定义 ContentProvider

AndroidManifest.xml 中定义 ContentProvider,并设置权限:

<provider
    android:name=".MyContentProvider"
    android:authorities="com.example.myapp.provider"
    android:exported="true"
    android:readPermission="com.example.myapp.READ_DATA"
    android:writePermission="com.example.myapp.WRITE_DATA" />
3. ContentProvider 实现

实现 ContentProvider 并处理权限:

public class MyContentProvider extends ContentProvider {
    private static final String AUTHORITY = "com.example.myapp.provider";
    private static final String BASE_PATH = "data";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);

    private static final int DATA = 1;
    private static final int DATA_ID = 2;
    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        uriMatcher.addURI(AUTHORITY, BASE_PATH, DATA);
        uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", DATA_ID);
    }

    private SQLiteDatabase database;

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

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        if (getContext().checkCallingOrSelfPermission("com.example.myapp.READ_DATA") != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Permission denied");
        }

        switch (uriMatcher.match(uri)) {
            case DATA:
                return database.query(DatabaseHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
            case DATA_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                return database.query(DatabaseHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        if (getContext().checkCallingOrSelfPermission("com.example.myapp.WRITE_DATA") != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Permission denied");
        }

        long id = database.insert(DatabaseHelper.TABLE_NAME, null, values);
        getContext().getContentResolver().notifyChange(uri, null);
        return ContentUris.withAppendedId(CONTENT_URI, id);
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        if (getContext().checkCallingOrSelfPermission("com.example.myapp.WRITE_DATA") != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Permission denied");
        }

        int rowsDeleted;
        switch (uriMatcher.match(uri)) {
            case DATA:
                rowsDeleted = database.delete(DatabaseHelper.TABLE_NAME, selection, selectionArgs);
                break;
            case DATA_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                rowsDeleted = database.delete(DatabaseHelper.TABLE_NAME, selection, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsDeleted;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        if (getContext().checkCallingOrSelfPermission("com.example.myapp.WRITE_DATA") != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Permission denied");
        }

        int rowsUpdated;
        switch (uriMatcher.match(uri)) {
            case DATA:
                rowsUpdated = database.update(DatabaseHelper.TABLE_NAME, values, selection, selectionArgs);
                break;
            case DATA_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                rowsUpdated = database.update(DatabaseHelper.TABLE_NAME, values, selection, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsUpdated;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (uriMatcher.match(uri)) {
            case DATA:
                return "vnd.android.cursor.dir/vnd.com.example.myapp.provider.data";
            case DATA_ID:
                return "vnd.android.cursor.item/vnd.com.example.myapp.provider.data";
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }
}

2. 实践案例:音乐播放器的播放列表管理

案例概述

假设我们正在开发一个音乐播放器应用,需要管理和共享播放列表。每个播放列表包含多个音乐文件。我们将使用 ContentProvider 来管理播放列表,并确保其他应用也可以访问这些播放列表。

1. 数据库设计
public class DatabaseHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "music.db";
    private static final int DATABASE_VERSION = 1;

    public static final String TABLE_PLAYLIST = "playlist";
    public static final String COLUMN_ID = "_id";
    public static final String COLUMN_NAME = "name";

    private static final String DATABASE_CREATE = "create table " 
        + TABLE_PLAYLIST + "(" 
        + COLUMN_ID + " integer primary key autoincrement, " 
        + COLUMN_NAME + " text not null);";

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase database) {
        database.execSQL(DATABASE_CREATE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_PLAYLIST);
        onCreate(db);
    }
}
2. ContentProvider 实现
public class PlaylistProvider extends ContentProvider {
    private static final String AUTHORITY = "com.example.musicplayer.provider";
    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 dbHelper = new DatabaseHelper(getContext());
        database = dbHelper.getWritableDatabase();
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        switch (uriMatcher.match(uri)) {
            case PLAYLISTS:
                return database.query(DatabaseHelper.TABLE_PLAYLIST, projection, selection, selectionArgs, null, null, sortOrder);
            case PLAYLIST_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                return database.query(DatabaseHelper.TABLE_PLAYLIST, projection, selection, selectionArgs, null, null, sortOrder);
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        long id = database.insert(DatabaseHelper.TABLE_PLAYLIST, null, values);
        getContext().getContentResolver().notifyChange(uri, null);
        return ContentUris.withAppendedId(CONTENT_URI, id);
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        int rowsDeleted;
        switch (uriMatcher.match(uri)) {
            case PLAYLISTS:
                rowsDeleted = database.delete(DatabaseHelper.TABLE_PLAYLIST, selection, selectionArgs);
                break;
            case PLAYLIST_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                rowsDeleted = database.delete(DatabaseHelper.TABLE_PLAYLIST, selection, selectionArgs);
                break;
           

 default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        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 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;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (uriMatcher.match(uri)) {
            case PLAYLISTS:
                return "vnd.android.cursor.dir/vnd.com.example.musicplayer.provider.playlists";
            case PLAYLIST_ID:
                return "vnd.android.cursor.item/vnd.com.example.musicplayer.provider.playlists";
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }
}

3. 总结

通过以上示例,我们展示了 ContentProvider 在跨应用数据共享、动态授权、数据观察和通知等方面的高级应用。通过合理设计 URI 结构、权限管理和数据缓存,可以有效提升 ContentProvider 的性能和安全性。在实际开发中,结合具体需求和场景,灵活运用这些高级技巧和最佳实践,是开发高效、可靠 Android 应用的关键。理解和掌握 ContentProvider 的高级使用方法,可以让开发者在数据管理和共享方面得心应手。

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

在这里插入图片描述

  • 12
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邓瑞军说HelloWorld

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值