文章目录
- 深入分析 Android ContentProvider (八)
- ContentProvider 高级使用及最佳实践案例分析(续)
- 1. 深入了解跨应用数据共享
- 示例:跨应用数据共享的完整实现
- 1. 定义权限
- 2. 定义 ContentProvider
- 3. ContentProvider 实现
- 2. 实践案例:音乐播放器的播放列表管理
- 案例概述
- 1. 数据库设计
- 2. ContentProvider 实现
- 3. 总结
深入分析 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 的高级使用方法,可以让开发者在数据管理和共享方面得心应手。
欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力 |