文章目录
深入分析 Android ContentProvider (六)
ContentProvider 的性能优化和实践案例(续)
在上一节中,我们介绍了 ContentProvider 的性能优化技巧和两个实际案例。本节将继续深入探讨更多的优化技巧,并提供更详细的实际案例分析。
1. 性能优化技巧(续)
1.6. 使用批量插入优化性能
在需要插入大量数据时,逐行插入会非常低效。可以使用 ContentProvider
的 bulkInsert
方法进行批量插入,从而显著提升性能。
示例:批量插入实现
@Override
public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
final SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case MEDIA:
db.beginTransaction();
try {
for (ContentValues value : values) {
db.insertOrThrow(DatabaseHelper.TABLE_MEDIA, null, value);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
getContext().getContentResolver().notifyChange(uri, null);
return values.length;
default:
return super.bulkInsert(uri, values);
}
}
1.7. 使用 Projections 优化查询
当查询数据库时,如果只需要部分字段,可以使用 Projections 来指定需要的列,以减少数据传输和内存消耗。
示例:使用 Projections
String[] projection = {
DatabaseHelper.COLUMN_ID,
DatabaseHelper.COLUMN_NAME
};
Cursor cursor = getContentResolver().query(
CONTENT_URI, // Uri
projection, // Projection
null, // Selection
null, // Selection arguments
null // Sort order
);
1.8. 减少频繁通知
在数据变化时,ContentProvider 会通知所有监听该 URI 的内容观察者。频繁的通知可能会导致性能问题。可以通过合并通知或使用 ContentResolver#notifyChange(Uri, ContentObserver, boolean)
的第三个参数控制通知范围。
示例:减少频繁通知
public int bulkUpdate(@NonNull Uri uri, @NonNull ContentValues[] values) {
final SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();
try {
for (ContentValues value : values) {
db.update(DatabaseHelper.TABLE_MEDIA, value, selection, selectionArgs);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
getContext().getContentResolver().notifyChange(uri, null, false);
return values.length;
}
1.9. 优化查询语句
复杂查询可能会降低性能,可以通过优化 SQL 语句,避免不必要的嵌套查询和表连接来提升性能。
示例:优化查询语句
Cursor cursor = db.query(
DatabaseHelper.TABLE_MEDIA,
projection,
DatabaseHelper.COLUMN_NAME + " LIKE ?",
new String[]{"%keyword%"},
null,
null,
DatabaseHelper.COLUMN_NAME + " ASC"
);
2. 实践案例(续)
2.3 案例三:联系人应用的数据管理
在联系人应用中,管理联系人数据需要高效的数据存储和检索。ContentProvider 可以提供统一的接口来管理联系人数据,并通过批量操作和异步任务优化性能。
联系人 ContentProvider 实现
public class ContactsProvider extends ContentProvider {
private static final String AUTHORITY = "com.example.contactsprovider";
private static final String BASE_PATH = "contacts";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);
private static final int CONTACTS = 1;
private static final int CONTACT_ID = 2;
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
uriMatcher.addURI(AUTHORITY, BASE_PATH, CONTACTS);
uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", CONTACT_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 CONTACTS:
return database.query(DatabaseHelper.TABLE_CONTACTS, projection, selection, selectionArgs, null, null, sortOrder);
case CONTACT_ID:
selection = DatabaseHelper.COLUMN_ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
return database.query(DatabaseHelper.TABLE_CONTACTS, 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_CONTACTS, 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 CONTACTS:
rowsDeleted = database.delete(DatabaseHelper.TABLE_CONTACTS, selection, selectionArgs);
break;
case CONTACT_ID:
selection = DatabaseHelper.COLUMN_ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
rowsDeleted = database.delete(DatabaseHelper.TABLE_CONTACTS, 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 CONTACTS:
rowsUpdated = database.update(DatabaseHelper.TABLE_CONTACTS, values, selection, selectionArgs);
break;
case CONTACT_ID:
selection = DatabaseHelper.COLUMN_ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
rowsUpdated = database.update(DatabaseHelper.TABLE_CONTACTS, 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 CONTACTS:
return "vnd.android.cursor.dir/vnd.com.example.contactsprovider.contacts";
case CONTACT_ID:
return "vnd.android.cursor.item/vnd.com.example.contactsprovider.contact";
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
}
2.4 案例四:日历应用的数据管理
在日历应用中,管理事件和提醒需要高效的数据存储和检索。通过 ContentProvider,可以方便地管理日历数据,并通过缓存机制和异步操作优化性能。
日历 ContentProvider 实现
public class CalendarProvider extends ContentProvider {
private static final String AUTHORITY = "com.example.calendarprovider";
private static final String BASE_PATH = "events";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);
private static final int EVENTS = 1;
private static final int EVENT_ID = 2;
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
uriMatcher.addURI(AUTHORITY, BASE_PATH, EVENTS);
uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", EVENT_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 EVENTS:
return database.query(DatabaseHelper.TABLE_EVENTS, projection, selection, selectionArgs, null, null, sortOrder);
case EVENT_ID:
selection = DatabaseHelper.COLUMN_ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
return database.query(DatabaseHelper.TABLE_EVENTS, 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_EVENTS, 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 EVENTS:
rowsDeleted = database.delete(DatabaseHelper.TABLE_EVENTS, selection, selectionArgs);
break;
case EVENT_ID:
selection = DatabaseHelper.COLUMN_ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
rowsDeleted = database.delete(DatabaseHelper.TABLE_EVENTS, 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 EVENTS:
rowsUpdated = database.update(DatabaseHelper.TABLE_EVENTS, values, selection, selectionArgs);
break;
case EVENT_ID:
selection = DatabaseHelper.COLUMN_ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
rowsUpdated = database.update(DatabaseHelper.TABLE_EVENTS, 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 EVENTS:
return "vnd.android.cursor.dir/vnd.com.example.calendarprovider.events";
case EVENT_ID:
return "vnd.android.cursor.item/vnd.com.example.calendarprovider.event";
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
}
3. 总结
ContentProvider 是 Android 中用于数据共享和管理的核心机制,特别适用于跨进程数据访问。在开发中,通过合理设计和优化,可以充分利用 ContentProvider 的优势,实现高效的数据操作。实践中,通过批量操作、异步任务、缓存机制等手段,可以显著提升 ContentProvider 的性能,确保应用的稳定性和用户体验。结合实际场景,选择合适的优化技巧和设计模式,是开发高性能 Android 应用的关键。
欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力 |