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