文章目录
- 深入分析 Android ContentProvider (六)
- ContentProvider 的性能优化和实践案例(续)
- 1. 性能优化技巧(续)
- 1.6. 使用批量插入优化性能
- 示例:批量插入实现
- 1.7. 使用 Projections 优化查询
- 示例:使用 Projections
- 1.8. 减少频繁通知
- 示例:减少频繁通知
- 1.9. 优化查询语句
- 示例:优化查询语句
- 2. 实践案例(续)
- 2.3 案例三:联系人应用的数据管理
- 联系人 ContentProvider 实现
- 2.4 案例四:日历应用的数据管理
- 日历 ContentProvider 实现
- 3. 总结
深入分析 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, // Uriprojection, // Projectionnull, // Selectionnull, // Selection argumentsnull // 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;@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 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@Overridepublic 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);}@Overridepublic 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;}@Overridepublic 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@Overridepublic 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;@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 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@Overridepublic 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);}@Overridepublic int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {introwsDeleted;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;}@Overridepublic 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@Overridepublic 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 应用的关键。
欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力 |