文章目录
- 深入分析 Android ContentProvider (八)
- ContentProvider 高级使用及最佳实践案例分析(续)
- 1. 深入了解跨应用数据共享
- 示例:跨应用数据共享的完整实现
- 1. 定义权限
- 2. 定义 ContentProvider
- 3. ContentProvider 实现
- 2. 实践案例:音乐播放器的播放列表管理
- 案例概述
- 1. 数据库设计
- 2. ContentProvider 实现
- 3. 总结
深入分析 Android ContentProvider (八)
ContentProvider 高级使用及最佳实践案例分析(续)
1. 深入了解跨应用数据共享
跨应用数据共享是 ContentProvider 的一个重要功能,它允许应用之间安全地共享数据。为此,我们需要定义清晰的权限和 URI 结构,以确保数据在不同应用之间安全传输。
示例:跨应用数据共享的完整实现
1. 定义权限
在 AndroidManifest.xml
中定义权限:
<permissionandroid:name="com.example.myapp.READ_DATA"android:protectionLevel="signature" />
<permissionandroid:name="com.example.myapp.WRITE_DATA"android:protectionLevel="signature" />
2. 定义 ContentProvider
在 AndroidManifest.xml
中定义 ContentProvider,并设置权限:
<providerandroid: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;@Overridepublic boolean onCreate() {DatabaseHelper dbHelper = new DatabaseHelper(getContext());database = dbHelper.getWritableDatabase();return true;}@Nullable@Overridepublic 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@Overridepublic 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);}@Overridepublic 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;}@Overridepublic 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@Overridepublic 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);}@Overridepublic void onCreate(SQLiteDatabase database) {database.execSQL(DATABASE_CREATE);}@Overridepublic 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;@Overridepublic boolean onCreate() {DatabaseHelper dbHelper = new DatabaseHelper(getContext());database = dbHelper.getWritableDatabase();return true;}@Nullable@Overridepublic 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@Overridepublic 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);}@Overridepublic 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;}@Overridepublic 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@Overridepublic 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 的高级使用方法,可以让开发者在数据管理和共享方面得心应手。
欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力 |