【问题标题】:Managing Memory Leaks in ContentProvider管理 ContentProvider 中的内存泄漏
【发布时间】:2017-02-09 14:47:01
【问题描述】:

我有一个 ContentProvider 类,我的活动使用它来访问、写入、查询和删除本地数据库中的数据。我在 ContentProvider 的方法中不断地打开我的数据库以访问数据。我的问题是,在 ContentProvider 中关闭数据库的合适位置在哪里?

我尝试在查询、插入和删除覆盖方法中执行此操作,但不断收到以下异常:

Caused by: java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.

这是我的 ContentProvider 类,后面是我的数据库类:

public class GroceryContentProvider extends ContentProvider {
final static int FOOD_ITEM = 100;
final static int FOOD_ITEM_WITH_ID = 101;
private UriMatcher uriMatcher = buildUriMatcher();
private final String TAG = "GROCERY_PROVIDER";

public static UriMatcher buildUriMatcher(){
    UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    uriMatcher.addURI(FoodContract.CONTENT_AUTHORITY,FoodContract.PATH,FOOD_ITEM);
    uriMatcher.addURI(FoodContract.CONTENT_AUTHORITY,FoodContract.PATH + "/#",FOOD_ITEM_WITH_ID);
    return uriMatcher;
}

@Override
public boolean onCreate() {
    return false;
}

@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    Cursor cursor;
    FoodDatabase foodDatabase = new FoodDatabase(getContext());
    int match = uriMatcher.match(uri);

    switch (match){
        case FOOD_ITEM:{
            foodDatabase.openReadableDB();
            cursor = foodDatabase.getAllRows(projection,selection,selectionArgs,sortOrder);

            break;
        }
        default:
            throw new UnsupportedOperationException("Unknown URI: " + uri);
    }
    cursor.setNotificationUri(getContext().getContentResolver(),uri);

    return cursor;
}

@Nullable
@Override
public String getType(Uri uri) {
    return null;
}

@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
    int match = uriMatcher.match(uri);
    Uri returnUri;
    switch (match){
        case FOOD_ITEM:{
            Context context = getContext();
            FoodDatabase foodDatabase = new FoodDatabase(context);
            foodDatabase.openWriteableDB();
            long id = foodDatabase.insertRow(values);
            if(id>0){
                returnUri = ContentUris.withAppendedId(FoodContract.FoodList.CONTENT_URI,id);
            }else{
                throw new android.database.SQLException("Failed to insert row into " + uri);
            }
            break;
        }
        default:
            throw new UnsupportedOperationException("Unknown URI: " + uri);
    }
    getContext().getContentResolver().notifyChange(uri,null);
    return returnUri;
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    int match = uriMatcher.match(uri);
    int taskDeleted;
    switch (match){
        case FOOD_ITEM_WITH_ID:{
            String idForDeletion = uri.getPathSegments().get(1);
            FoodDatabase foodDatabase = new FoodDatabase(getContext());
            foodDatabase.openWriteableDB();
            taskDeleted = foodDatabase.deleteRow(FoodContract.FoodList.TABLE_NAME,"_id=?",new String[]{idForDeletion});
            break;
        }
        default:
            throw new UnsupportedOperationException("URI UNKNOWN " + uri);
    }
    if(taskDeleted!=0){
        getContext().getContentResolver().notifyChange(uri,null);
    }

    return taskDeleted;
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    return 0;
}}

数据库:

public class FoodDatabase {
private SQLiteDatabase db;
private DatabaseHelper databaseHelper;
private Context context;
public static final int DB_VERSION = 1;
public static final String DB_NAME = "food_list_db";

private final String CREATE_DATABASE = "CREATE TABLE " + FoodContract.FoodList.TABLE_NAME + " ("
        + FoodContract.FoodList._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
        + FoodContract.FoodList.ITEM_NAME + " TEXT NOT NULL"
        + ");";


public FoodDatabase(Context context){
    this.context = context;
    databaseHelper = new DatabaseHelper(context);
}

public FoodDatabase openWriteableDB(){
    db = databaseHelper.getWritableDatabase();
    return this;
}

public FoodDatabase openReadableDB(){
    db = databaseHelper.getReadableDatabase();
    return this;
}

public long insertRow(ContentValues cv){
    return db.insert(FoodContract.FoodList.TABLE_NAME,null,cv);
}

public Cursor getAllRows(String[] projection, String selection, String[] selectionArgs, String sortOrder){
    return db.query(FoodContract.FoodList.TABLE_NAME,projection,selection,selectionArgs,null,null,sortOrder);
}

public int deleteRow(String table, String whereClause, String[]whereArgs){
    return db.delete(table,whereClause,whereArgs);
}

public void closeDB(){
    db.close();
}

private class DatabaseHelper extends SQLiteOpenHelper {
    public DatabaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_DATABASE);

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + FoodContract.FoodList.TABLE_NAME);
        onCreate(db);
    }
}}

【问题讨论】:

标签: android android-contentprovider


【解决方案1】:

我建议你更改内容提供者的onCreate 方法,在成员变量mFoodDatabase 中初始化FoodDatabase 类:

@Override
public boolean onCreate() {
    mFoodDatabase = new FoodDatabase(getContext());
    return true;
}

并且,在您的内容提供程序方法(查询、插入、更新和删除)中,尝试使用存储在成员变量 mFoodDatabase 中的对象,而不是重新实例化 FoodDatabase 对象。

希望能帮到你

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-08
    • 2012-05-19
    • 2018-06-19
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多