dimanche 17 avril 2016

DatabaseObjectNotClosedException when notifydatasetChanged

Main activity

When I am refreshing UI with mPageAdapter.notifyDataSetChanged(), I always get below warning message:

04-17 19:08:52.286 11879-11904/com.android.todolist1 E/CursorLeakDetecter: PossibleCursorLeak:content://com.todolist.provider.taskprovider/task,QueryCounter:9 android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here at android.content.ContentResolver.query(ContentResolver.java:399) at android.content.ContentResolver.query(ContentResolver.java:316) at android.content.AsyncQueryHandler$WorkerHandler.handleMessage(AsyncQueryHandler.java:79) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:237) at android.os.HandlerThread.run(HandlerThread.java:60) 04-17 19:08:52.296 11879-11904/com.android.todolist1 E/CursorLeakDetecter: PossibleCursorLeak:content://com.todolist.provider.taskprovider/task,QueryCounter:10 android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here at android.content.ContentResolver.query(ContentResolver.java:399) at android.content.ContentResolver.query(ContentResolver.java:316) at android.content.AsyncQueryHandler$WorkerHandler.handleMessage(AsyncQueryHandler.java:79) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:237) at android.os.HandlerThread.run(HandlerThread.java:60)

Here is my TaskProvider.java:

package com.android.todolist1;


public class TaskProvider extends ContentProvider {

public static final String CONTENT_TYPE = "http://ift.tt/1Sk6owQ";
public static final String CONTENT_ITEM_TYPE = "http://ift.tt/1VaJtrv";
public static final String TASK_PROVIDER =
        "content://com.todolist.provider.taskprovider/task";
public static final Uri CONTENT_TASK_URI = Uri.parse(TASK_PROVIDER);

private static final int TASK_ALL = 0;
private static final int TASK_ONE = 1;
private static final UriMatcher matcher;
private static final String TAG = "TaskProvider";
private static final String TABLE_NAME = "tasks";
private static final String AUTHORITY = "com.todolist.provider.taskprovider";
//数据改变后立即重新查询,##check##检查有没有s
private static final Uri NOTIFY_URI = Uri.parse("content://" + AUTHORITY + "/tasks");
private DBHelper helper;
private SQLiteDatabase db;

static {
    matcher = new UriMatcher(UriMatcher.NO_MATCH);
    matcher.addURI(AUTHORITY, "task", TASK_ALL);     //匹配记录集合
    matcher.addURI(AUTHORITY, "task/#", TASK_ONE);   //匹配单条记录
}

@Override
public boolean onCreate() {
    helper = new DBHelper(getContext());
    return true;
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    db = helper.getWritableDatabase();
    int match = matcher.match(uri);
    switch (match) {
    case TASK_ALL:
        //doesn't need any code in my provider.
        break;
    case TASK_ONE:
        long _id = ContentUris.parseId(uri);
        selection = "_id = ?";
        selectionArgs = new String[]{String.valueOf(_id)};
    }
    int count = db.delete(TABLE_NAME, selection, selectionArgs);
    if (count > 0) {
        notifyDataChanged();
    }
    db.close();
    return count;
}

@Override
public String getType(Uri uri) {
    int match = matcher.match(uri);
    switch (match) {
    case TASK_ALL:
        return CONTENT_TYPE;
    case TASK_ONE:
        return CONTENT_ITEM_TYPE;
    default:
        throw new IllegalArgumentException("Unknown URI: " + uri);
    }
}

@Override
public Uri insert(Uri uri, ContentValues values) {
    int match = matcher.match(uri);
    if (match != TASK_ALL) {
        throw new IllegalArgumentException("Wrong URI when insert: " + uri);
    }
    db = helper.getWritableDatabase();
    if (values == null) {
        values = new ContentValues();
        values.put("color", "0");
        values.put("title", "no title");
        values.put("summary", "carrot, cucumber, apple, \ntapes, \nicecream\ngrapes");
    }
    long rowId = db.insert(TABLE_NAME, null, values);
    if (rowId > 0) {
        notifyDataChanged();
        db.close();
        return ContentUris.withAppendedId(uri, rowId);
    }
    db.close();
    return null;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {
    db = helper.getReadableDatabase();
    int match = matcher.match(uri);
    switch (match) {
    case TASK_ALL:
        //doesn't need any code in my provider.
        break;
    case TASK_ONE:
        long _id = ContentUris.parseId(uri);
        selection = TaskColumns.ID + " = ?";
        selectionArgs = new String[]{String.valueOf(_id)};
        //或者可以选择以下方式
        //selection = "_id = " + _id;
        break;
    default:
        throw new IllegalArgumentException("Unknown URI when query: " + uri);
    }
    Cursor cursor = db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
    return cursor;
}

@Override
public int update(Uri uri, ContentValues values, String selection,
        String[] selectionArgs) {
    db = helper.getWritableDatabase();
    int match = matcher.match(uri);
    switch (match) {
    case TASK_ALL:
        //doesn't need any code in my provider.
        break;
    case TASK_ONE:
        long _id = ContentUris.parseId(uri);
        selection = TaskColumns.ID +  " = ?";
        selectionArgs = new String[]{String.valueOf(_id)};
        break;
    default:
        throw new IllegalArgumentException("Unknown URI when update: " + uri);
    }
    int count = db.update(TABLE_NAME, values, selection, selectionArgs);
    if (count > 0) {
        notifyDataChanged();
    }
    db.close();
    return count;
}

//通知指定URI数据已改变
private void notifyDataChanged() {
    getContext().getContentResolver().notifyChange(NOTIFY_URI, null);       
}

private class DBHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "provider.db";
    private static final int DATABASE_VERSION = 1;

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

        final String CREATE_TABLE_SQL = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + "(" +
                TaskColumns.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                TaskColumns.COLOR + " INTEGER NOT NULL DEFAULT 0," +
                TaskColumns.STATE + " INTEGER NOT NULL DEFAULT 0," +
                TaskColumns.TITLE + " TEXT NOT NULL DEFAULT ''," +
                TaskColumns.SUMMARY + " TEXT NOT NULL DEFAULT ''," +
                TaskColumns.TIME + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
                TaskColumns.ALARM_TIME + " INTEGER NOT NULL DEFAULT 0," +
                TaskColumns.MODIFIED_TIME + " INTEGER NOT NULL DEFAULT 0," +
                TaskColumns.HAS_ALARM + " INTEGER NOT NULL DEFAULT 0," +
                TaskColumns.HAS_REPETITION + " TEXT NOT NULL DEFAULT 0" + ");";
        db.execSQL(CREATE_TABLE_SQL);

        //insert default alarms
        String insertMe = "INSERT INTO tasks " +
            "(color, state, title, summary, time, alarmTime, modifyTime, hasAlarm, hasRepetition) VALUES ";
        db.execSQL(insertMe + "(0, 0, 'meal', 'n/a', '1000000', '1000000', '10000'"
                + ", 0, 'NA');");
        db.execSQL(insertMe + "(1, 1, 'pay the bill', 'credit card', '2000000', '10000',"
                + " '22000000', 1, '1d');");
        db.execSQL(insertMe + "(2, 2, 'make a call', 'this is very important\nemergency\nadd',"
                + " '303000000', '3030000000', '10000', 1, '5m');");
    }

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

/**
 * Create a new task id for adding a new task to databases
 */
public static synchronized int getNewTaskId(Context context) {
    ContentValues values = new ContentValues();
    long createdTime = System.currentTimeMillis();
    values.put(TaskColumns.MODIFIED_TIME, createdTime);
    Uri uri = context.getContentResolver().insert(CONTENT_TASK_URI, values);

    int taskId = -1;
    try {
        taskId = Integer.valueOf(uri.getPathSegments().get(1));
    } catch (NumberFormatException e) {
        Log.e(TAG, "Get note id error :" + e.toString());
    }
    if (taskId < 0) {
        throw new IllegalStateException("Wrong note id: " + taskId);
    }
    return taskId;
}

public static boolean deleteSingleTask(Context context, long id) {
    Uri uri = ContentUris.withAppendedId(CONTENT_TASK_URI, id);
    int result = context.getContentResolver().delete(uri, null, null);
    if (result == 0) {
        Log.d(TAG, "delete notes failed, id:" + id);
        return false;
    }
    return false;
}


}

I have closed my db in insert() delete() and update(), why is there still DatabaseObjectNotClosedException?

Thanks a lot.

Aucun commentaire:

Enregistrer un commentaire