管理ContentProvider中的内存泄漏

时间:2017-02-08 20:48:08

标签: android android-contentprovider

我有一个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);
    }
}}

1 个答案:

答案 0 :(得分:2)

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

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

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

希望可以提供帮助