0


深入分析 Android ContentProvider (五)

文章目录

深入分析 Android ContentProvider (五)

ContentProvider 的性能优化和实践案例

在实践中,合理的性能优化可以显著提升 ContentProvider 的效率和用户体验。以下是一些具体的性能优化技巧和实际案例,以便更好地理解和应用 ContentProvider。

1. 性能优化技巧

1.1. 数据库索引优化

在频繁进行查询操作的字段上添加索引,可以显著提高查询性能。数据库索引可以加快数据检索的速度,尤其是在大型数据集上。

示例:添加索引

在创建数据库表时,可以通过 SQL 语句为某些列创建索引:

privatestaticfinalStringCREATE_TABLE="CREATE TABLE "+TABLE_NAME+" ("+COLUMN_ID+" INTEGER PRIMARY KEY AUTOINCREMENT, "+COLUMN_NAME+" TEXT NOT NULL);";privatestaticfinalStringCREATE_INDEX="CREATE INDEX index_name ON "+TABLE_NAME+" ("+COLUMN_NAME+");";@OverridepublicvoidonCreate(SQLiteDatabase db){
    db.execSQL(CREATE_TABLE);
    db.execSQL(CREATE_INDEX);}
1.2. 批量操作与事务管理

在执行大批量的数据插入、更新或删除操作时,使用事务可以减少数据库锁的开销,并提高操作的整体性能。

示例:批量插入操作
publicvoidbulkInsertData(List<ContentValues> valuesList){SQLiteDatabase db = dbHelper.getWritableDatabase();
    db.beginTransaction();try{for(ContentValues values : valuesList){
            db.insertOrThrow(TABLE_NAME,null, values);}
        db.setTransactionSuccessful();}finally{
        db.endTransaction();}}
1.3. 使用异步操作

避免在主线程中进行数据库操作,使用

AsyncTask

Loader

RxJava

等异步框架进行数据操作,确保应用的 UI 流畅性。

示例:使用 AsyncTask 进行异步查询
privateclassQueryTaskextendsAsyncTask<Void,Void,Cursor>{@OverrideprotectedCursordoInBackground(Void... voids){Uri uri =Uri.parse("content://com.example.provider/examples");returngetContentResolver().query(uri,null,null,null,"name ASC");}@OverrideprotectedvoidonPostExecute(Cursor cursor){if(cursor !=null){// 处理查询结果
            cursor.close();}}}
1.4. 缓存机制

在数据访问频繁的场景中,使用缓存机制可以显著提高性能。可以选择内存缓存(如 LruCache)或磁盘缓存来缓存常用数据,减少数据库查询的次数。

示例:使用 LruCache 进行内存缓存
privateLruCache<String,Bitmap> memoryCache;publicvoidinitCache(){finalint maxMemory =(int)(Runtime.getRuntime().maxMemory()/1024);finalint cacheSize = maxMemory /8;
    memoryCache =newLruCache<>(cacheSize);}publicvoidaddBitmapToCache(String key,Bitmap bitmap){if(getBitmapFromCache(key)==null){
        memoryCache.put(key, bitmap);}}publicBitmapgetBitmapFromCache(String key){return memoryCache.get(key);}
1.5. 使用 Loader 进行异步加载

Loader 可以在异步线程中加载数据,避免主线程阻塞,并在数据加载完成时自动更新 UI。

示例:使用 CursorLoader
publicclassExampleActivityextendsAppCompatActivityimplementsLoaderManager.LoaderCallbacks<Cursor>{privatestaticfinalintLOADER_ID=1;@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_example);getSupportLoaderManager().initLoader(LOADER_ID,null,this);}@NonNull@OverridepublicLoader<Cursor>onCreateLoader(int id,@NullableBundle args){Uri uri =Uri.parse("content://com.example.provider/examples");returnnewCursorLoader(this, uri,null,null,null,"name ASC");}@OverridepublicvoidonLoadFinished(@NonNullLoader<Cursor> loader,Cursor data){// 更新 UI}@OverridepublicvoidonLoaderReset(@NonNullLoader<Cursor> loader){// 清理资源}}

2. 实践案例

2.1 案例一:消息应用的数据同步

在消息应用中,消息数据通常需要在客户端和服务器之间同步。使用 ContentProvider,可以方便地实现数据的本地存储和跨进程访问,同时结合 Loader 和异步任务,确保数据加载和更新的流畅性。

消息 ContentProvider 实现
publicclassMessageProviderextendsContentProvider{privatestaticfinalStringAUTHORITY="com.example.provider";privatestaticfinalStringBASE_PATH="messages";publicstaticfinalUriCONTENT_URI=Uri.parse("content://"+AUTHORITY+"/"+BASE_PATH);privatestaticfinalintMESSAGES=1;privatestaticfinalintMESSAGE_ID=2;privatestaticfinalUriMatcher uriMatcher =newUriMatcher(UriMatcher.NO_MATCH);static{
        uriMatcher.addURI(AUTHORITY,BASE_PATH,MESSAGES);
        uriMatcher.addURI(AUTHORITY,BASE_PATH+"/#",MESSAGE_ID);}privateSQLiteDatabase database;@OverridepublicbooleanonCreate(){DatabaseHelper dbHelper =newDatabaseHelper(getContext());
        database = dbHelper.getWritableDatabase();returntrue;}@Nullable@OverridepublicCursorquery(@NonNullUri uri,@NullableString[] projection,@NullableString selection,@NullableString[] selectionArgs,@NullableString sortOrder){switch(uriMatcher.match(uri)){caseMESSAGES:return database.query(DatabaseHelper.TABLE_MESSAGES, projection, selection, selectionArgs,null,null, sortOrder);caseMESSAGE_ID:
                selection =DatabaseHelper.COLUMN_ID+"=?";
                selectionArgs =newString[]{String.valueOf(ContentUris.parseId(uri))};return database.query(DatabaseHelper.TABLE_MESSAGES, projection, selection, selectionArgs,null,null, sortOrder);default:thrownewIllegalArgumentException("Unknown URI: "+ uri);}}@Nullable@OverridepublicUriinsert(@NonNullUri uri,@NullableContentValues values){long id = database.insert(DatabaseHelper.TABLE_MESSAGES,null, values);getContext().getContentResolver().notifyChange(uri,null);returnContentUris.withAppendedId(CONTENT_URI, id);}@Overridepublicintdelete(@NonNullUri uri,@NullableString selection,@NullableString[] selectionArgs){int rowsDeleted;switch(uriMatcher.match(uri)){caseMESSAGES:
                rowsDeleted = database.delete(DatabaseHelper.TABLE_MESSAGES, selection, selectionArgs);break;caseMESSAGE_ID:
                selection =DatabaseHelper.COLUMN_ID+"=?";
                selectionArgs =newString[]{String.valueOf(ContentUris.parseId(uri))};
                rowsDeleted = database.delete(DatabaseHelper.TABLE_MESSAGES, selection, selectionArgs);break;default:thrownewIllegalArgumentException("Unknown URI: "+ uri);}getContext().getContentResolver().notifyChange(uri,null);return rowsDeleted;}@Overridepublicintupdate(@NonNullUri uri,@NullableContentValues values,@NullableString selection,@NullableString[] selectionArgs){int rowsUpdated;switch(uriMatcher.match(uri)){caseMESSAGES:
                rowsUpdated = database.update(DatabaseHelper.TABLE_MESSAGES, values, selection, selectionArgs);break;caseMESSAGE_ID:
                selection =DatabaseHelper.COLUMN_ID+"=?";
                selectionArgs =newString[]{String.valueOf(ContentUris.parseId(uri))};
                rowsUpdated = database.update(DatabaseHelper.TABLE_MESSAGES, values, selection, selectionArgs);break;default:thrownewIllegalArgumentException("Unknown URI: "+ uri);}getContext().getContentResolver().notifyChange(uri,null);return rowsUpdated;}@Nullable@OverridepublicStringgetType(@NonNullUri uri){switch(uriMatcher.match(uri)){caseMESSAGES:return"vnd.android.cursor.dir/vnd.com.example.provider.messages";caseMESSAGE_ID:return"vnd.android.cursor.item/vnd.com.example.provider.message";default:thrownewIllegalArgumentException("Unknown URI: "+ uri);}}}
2.2 案例二:音乐播放器的媒体库管理

在音乐播放器应用中,媒体库管理需要高效的数据存储和查询功能。ContentProvider 可以为应用提供统一的数据访问接口,并结合批量操作和事务管理,实现高效的数据管理。

媒体库 ContentProvider 实现
publicclassMediaProviderextendsContentProvider{privatestaticfinalStringAUTHORITY="com.example.provider";privatestaticfinalStringBASE_PATH="media";publicstaticfinalUriCONTENT_URI=Uri.parse("content://"+AUTHORITY+"/"+BASE_PATH);privatestaticfinalintMEDIA=1;privatestaticfinalintMEDIA_ID=2;privatestaticfinalUriMatcher uriMatcher =newUriMatcher(UriMatcher.NO_MATCH);static{
        uriMatcher.addURI(AUTHORITY,BASE_PATH,MEDIA);
        uriMatcher.addURI(AUTHORITY,BASE_PATH+"/#",MEDIA_ID);}privateSQLiteDatabase database;@OverridepublicbooleanonCreate(){DatabaseHelper dbHelper =newDatabaseHelper(getContext());
        database = dbHelper.getWritableDatabase();returntrue;}@Nullable@OverridepublicCursorquery(@NonNullUri uri,@NullableString[] projection,@NullableString selection,@NullableString[] selectionArgs,@NullableString sortOrder){switch(uriMatcher.match(uri)){caseMEDIA:return database.query(DatabaseHelper.TABLE_MEDIA, projection, selection, selectionArgs,null,null, sortOrder);caseMEDIA_ID:
                selection =DatabaseHelper.COLUMN_ID+"=?";
                selectionArgs =newString[]{String.valueOf(ContentUris.parseId(uri))};return database.query(DatabaseHelper.TABLE_MEDIA, projection, selection, selectionArgs,null,null, sortOrder);default:thrownewIllegalArgumentException("Unknown URI: "+ uri);}}@Nullable@OverridepublicUriinsert(@NonNullUri uri,@NullableContentValues values){long id = database.insert(DatabaseHelper.TABLE_MEDIA,null, values);getContext().getContentResolver().notifyChange(uri,null);returnContentUris.withAppendedId(CONTENT_URI, id);}@Overridepublicintdelete(@NonNullUri uri,@NullableString selection,@NullableString[] selectionArgs){int rowsDeleted;switch(uriMatcher.match(uri)){caseMEDIA:
                rowsDeleted = database.delete(DatabaseHelper.TABLE_MEDIA, selection, selectionArgs);break;caseMEDIA_ID:
                selection =DatabaseHelper.COLUMN_ID+"=?";
                selectionArgs =newString[]{String.valueOf(ContentUris.parseId(uri))};
                rowsDeleted = database.delete(DatabaseHelper.TABLE_MEDIA, selection, selectionArgs);break;default:thrownewIllegalArgumentException("Unknown URI: "+ uri);}getContext().getContentResolver().notifyChange(uri,null);return rowsDeleted;}@Overridepublicintupdate(@NonNullUri uri,@NullableContentValues values,@NullableString selection,@NullableString[] selectionArgs){int rowsUpdated;switch(uriMatcher.match(uri)){caseMEDIA:
                rowsUpdated = database.update(DatabaseHelper.TABLE_MEDIA, values, selection, selectionArgs);break;caseMEDIA_ID:
                selection =DatabaseHelper.COLUMN_ID+"=?";
                selectionArgs =newString[]{String.valueOf(ContentUris.parseId(uri))};
                rowsUpdated = database.update(DatabaseHelper.TABLE_MEDIA, values, selection, selectionArgs);break;default:thrownewIllegalArgumentException("Unknown URI: "+ uri);}getContext().getContentResolver().notifyChange(uri,null);return rowsUpdated;}@Nullable@OverridepublicStringgetType(@NonNullUri uri){switch(uriMatcher.match(uri)){caseMEDIA:return"vnd.android.cursor.dir/vnd.com.example.provider.media";caseMEDIA_ID:return"vnd.android.cursor.item/vnd.com.example.provider.media";default:thrownewIllegalArgumentException("Unknown URI: "+ uri);}}}

3. 总结

ContentProvider 是 Android 中强大的数据共享和管理机制,尤其适用于跨进程数据共享和提供统一的数据访问接口。在实际应用中,通过合理设计和优化,可以充分发挥 ContentProvider 的优势,确保数据操作的高效性和安全性。遵循最佳实践并结合具体场景进行性能优化,可以显著提升应用的用户体验和稳定性。
欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力
在这里插入图片描述


本文转载自: https://blog.csdn.net/rjdeng/article/details/139655605
版权归原作者 邓瑞军说HelloWorld 所有, 如有侵权,请联系我们删除。

“深入分析 Android ContentProvider (五)”的评论:

还没有评论