我在自己的db框架中遇到了这个问题。我在StackOverflow中搜索了这个问题,并尝试了前面提到的许多方法,但这个问题并没有得到解决。当我尝试更新列表项时,它在单线程中工作得很好,这通常是应用程序小部件中的occor问题。
解释如下:
1.这是用于获取SQLiteDatabase对象的SQLiteOpenHelper,您可以看到它是单例的:
public class PalmDB extends SQLiteOpenHelper {
public static PalmDB getInstance(final Context context){
if (sInstance == null){
synchronized (PalmDB.class) {
if (sInstance == null) {
sInstance = new PalmDB(context.getApplicationContext());
}
}
}
return sInstance;
}
}
2、接下来是用于查询数据并将数据保存到数据库的存储区。它是抽象的:
public abstract class BaseStore<T extends Model> {
private PalmDB mPalmDatabase = null;
@SuppressWarnings("unchecked")
public BaseStore(Context context) {
this.mPalmDatabase = PalmDB.getInstance(context);
}
protected SQLiteDatabase getWritableDatabase() {
return mPalmDatabase.getWritableDatabase();
}
protected synchronized void closeCursor(Cursor cursor) {
if (cursor == null || cursor.isClosed()) return;
try {
cursor.close();
} catch (Exception e){
LogUtils.d("Couldn't close cursor correctly");
}
}
public synchronized List<T> get(String whereSQL, String orderSQL, Status status, boolean exclude) {
Cursor cursor = null;
List<T> models = null;
SQLiteDatabase database = getWritableDatabase();
try {
cursor = database.rawQuery(" SELECT * FROM " + tableName
+ " WHERE " + BaseSchema.USER_ID + " = " + userId
+ (TextUtils.isEmpty(whereSQL) ? "" : " AND " + whereSQL)
+ (status == null ? "" : " AND " + BaseSchema.STATUS + (exclude ? " != " : " = ") + status.id)
+ (TextUtils.isEmpty(orderSQL) ? "" : " ORDER BY " + orderSQL),
new String[]{});
models = getList(cursor);
} finally {
closeCursor(cursor);
}
return models;
}
protected synchronized List<T> getList(Cursor cursor){
LogUtils.d(this); // print the hash code of this object
LogUtils.d(Thread.currentThread());
List<T> models = new LinkedList<>();
if (cursor != null && !cursor.isClosed() && cursor.moveToFirst()){ // exception here
do {
models.add(getModel(cursor));
} while (cursor.moveToNext());
} else if (cursor != null && cursor.isClosed()) {
LogUtils.e("cursor is closed : " + cursor);
}
return models;
}
private T getModel(Cursor cursor) {
T model = StoreHelper.getBaseModel(cursor, entityClass);
fillModel(model, cursor);
return model;
}
然后我重写这个类来表示这样的具体对象。正如您所看到的,它也是单例的:
public class MindSnaggingStore extends BaseStore<MindSnagging> {
private static MindSnaggingStore sInstance = null;
public static MindSnaggingStore getInstance(Context context){
if (sInstance == null){
synchronized (MindSnaggingStore.class) {
if (sInstance == null) {
sInstance = new MindSnaggingStore(context.getApplicationContext());
}
}
}
return sInstance;
}
private MindSnaggingStore(Context context) {
super(context);
}
}
它在活动和片段中运行良好,但当我将其包含在应用程序小部件中时。当我尝试删除任何实体时,通常是两次,然后它崩溃了。
例外情况如下:
02-05 20:01:58.497 19317-19330/? E/AndroidRuntime: FATAL EXCEPTION: Binder:19317_1
Process: me.shouheng.notepal, PID: 19317
java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:962)
at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:599)
at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:834)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:143)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:132)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:219)
at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:258)
at me.shouheng.notepal.provider.BaseStore.getList(BaseStore.java:330)
at me.shouheng.notepal.provider.BaseStore.get(BaseStore.java:127)
at me.shouheng.notepal.provider.BaseStore.get(BaseStore.java:101)
at me.shouheng.notepal.widget.desktop.ListRemoteViewsFactory.getNotes(ListRemoteViewsFactory.java:72)
at me.shouheng.notepal.widget.desktop.ListRemoteViewsFactory.setupModels(ListRemoteViewsFactory.java:63)
at me.shouheng.notepal.widget.desktop.ListRemoteViewsFactory.onDataSetChanged(ListRemoteViewsFactory.java:86)
at android.widget.RemoteViewsService$RemoteViewsFactoryAdapter.onDataSetChanged(RemoteViewsService.java:142)
at com.android.internal.widget.IRemoteViewsFactory$Stub.onTransact(IRemoteViewsFactory.java:49)
at android.os.Binder.execTransact(Binder.java:565)
我确实将同步化添加到了重要的方法中,而db类是singleton,我想知道为什么我仍然会遇到这个问题。
更多信息。下面是我的日志,我打印了线程、数据库和存储对象:
02-05 22:41:53.119 15712-15712/me.shouheng.notepal D/colorful: ThemeDelegate fetched theme in 1 ms
02-05 22:41:53.305 3030-3149/system_process I/ActivityManager: Displayed me.shouheng.notepal/.activity.TrashedActivity: +235ms
02-05 22:41:53.648 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.NotebookStore@76f9b87
02-05 22:41:53.649 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[main,5,main]
02-05 22:41:53.656 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.NotesStore@f4252
02-05 22:41:53.656 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[main,5,main]
02-05 22:41:58.018 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:41)#<init> ] me.shouheng.notepal.provider.PalmDB@a34edfa
02-05 22:41:58.057 15712-15712/me.shouheng.notepal D/NotePal: [ (AppWidgetUtils.java:20)#NotifyAppWidgets ] Notifies AppWidget data changed for widgets [87, 85]
02-05 22:41:58.061 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.NotebookStore@76f9b87
02-05 22:41:58.062 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[main,5,main]
02-05 22:41:58.071 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.NotesStore@f4252
02-05 22:41:58.072 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[main,5,main]
02-05 22:41:58.155 15712-15712/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:51)#OnCreate ] Created widget 87
02-05 22:41:58.157 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:41)#<init> ] me.shouheng.notepal.provider.PalmDB@a34edfa
02-05 22:41:58.158 15712-15712/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:78)#GetMinds ] me.shouheng.notepal.provider.MindSnaggingStore@f341cfd
02-05 22:41:58.158 15712-15712/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:79)#GetMinds ] Thread[main,5,main]
02-05 22:41:58.160 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.MindSnaggingStore@f341cfd
02-05 22:41:58.161 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[main,5,main]
02-05 22:41:58.169 15712-15712/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:51)#OnCreate ] Created widget 85
02-05 22:41:58.171 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.NotesStore@f4252
02-05 22:41:58.172 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[main,5,main]
02-05 22:41:58.172 15712-16198/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:85)#OnDataSetChanged ] onDataSetChanged widget 87
02-05 22:41:58.173 15712-16198/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:78)#GetMinds ] me.shouheng.notepal.provider.MindSnaggingStore@f341cfd
02-05 22:41:58.173 15712-16198/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:79)#GetMinds ] Thread[Binder:15712_3,5,main]
02-05 22:41:58.174 15712-16198/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.MindSnaggingStore@f341cfd
02-05 22:41:58.175 15712-16198/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[Binder:15712_3,5,main]
02-05 22:41:58.177 15712-15725/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:85)#OnDataSetChanged ] onDataSetChanged widget 85
02-05 22:41:58.178 15712-15725/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.NotesStore@f4252
02-05 22:41:58.178 15712-15725/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[Binder:15712_1,5,main]
02-05 22:41:58.179 3030-4466/system_process W/InputMethodManagerService: Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@86f53ab attribute=null, token = android.os.BinderProxy@8dfbb89
02-05 22:41:58.483 15712-16191/me.shouheng.notepal D/OpenGLRenderer: endAllActiveAnimators on 0xc8ecfc00 (MenuPopupWindow$MenuDropDownListView) with handle 0xc8eb0540
02-05 22:41:58.933 3030-3485/system_process D/AudioService: Stream muted, skip playback
02-05 22:41:59.775 3030-3485/system_process D/AudioService: Stream muted, skip playback
02-05 22:41:59.804 15712-15712/me.shouheng.notepal D/NotePal: [ (AppWidgetUtils.java:20)#NotifyAppWidgets ] Notifies AppWidget data changed for widgets [87, 85]
02-05 22:41:59.807 15712-15725/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:85)#OnDataSetChanged ] onDataSetChanged widget 87
02-05 22:41:59.807 15712-16198/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:85)#OnDataSetChanged ] onDataSetChanged widget 85
02-05 22:41:59.808 15712-15725/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:78)#GetMinds ] me.shouheng.notepal.provider.MindSnaggingStore@f341cfd
02-05 22:41:59.808 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.NotebookStore@76f9b87
02-05 22:41:59.808 15712-15725/me.shouheng.notepal D/NotePal: [ (ListRemoteViewsFactory.java:79)#GetMinds ] Thread[Binder:15712_1,5,main]
02-05 22:41:59.808 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[main,5,main]
02-05 22:41:59.808 15712-16198/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.NotesStore@f4252
02-05 22:41:59.808 15712-15725/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.MindSnaggingStore@f341cfd
02-05 22:41:59.810 15712-16198/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[Binder:15712_3,5,main]
02-05 22:41:59.810 15712-15712/me.shouheng.notepal I/SQLiteConnectionPool: The connection pool for /data/user/0/me.shouheng.notepal/databases/NotePal.db has been closed but there are still 1 connections in use. They will be closed as they are released back to the pool.
02-05 22:41:59.811 15712-15725/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[Binder:15712_1,5,main]
02-05 22:41:59.828 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:327)#GetList ] me.shouheng.notepal.provider.NotesStore@f4252
02-05 22:41:59.829 15712-15712/me.shouheng.notepal D/NotePal: [ (BaseStore.java:328)#GetList ] Thread[main,5,main]
02-05 22:41:59.867 15712-15717/me.shouheng.notepal I/art: Do full code cache collection, code=97KB, data=125KB
02-05 22:41:59.868 15712-15717/me.shouheng.notepal I/art: Starting a blocking GC JitCodeCache
02-05 22:41:59.868 15712-15717/me.shouheng.notepal I/art: After code cache collection, code=79KB, data=87KB
02-05 22:41:59.899 3030-14418/system_process W/InputMethodManagerService: Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@9aae3c6 attribute=null, token = android.os.BinderProxy@8dfbb89
02-05 22:41:59.957 15712-15725/me.shouheng.notepal E/AndroidRuntime: FATAL EXCEPTION: Binder:15712_1
Process: me.shouheng.notepal, PID: 15712
java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:962)
at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:599)
at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:834)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:143)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:132)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:219)
at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:258)
at me.shouheng.notepal.provider.BaseStore.getList(BaseStore.java:330)
at me.shouheng.notepal.provider.BaseStore.get(BaseStore.java:127)
at me.shouheng.notepal.provider.BaseStore.get(BaseStore.java:101)
at me.shouheng.notepal.widget.desktop.ListRemoteViewsFactory.getMinds(ListRemoteViewsFactory.java:80)
at me.shouheng.notepal.widget.desktop.ListRemoteViewsFactory.setupModels(ListRemoteViewsFactory.java:65)
at me.shouheng.notepal.widget.desktop.ListRemoteViewsFactory.onDataSetChanged(ListRemoteViewsFactory.java:86)
at android.widget.RemoteViewsService$RemoteViewsFactoryAdapter.onDataSetChanged(RemoteViewsService.java:142)
at com.android.internal.widget.IRemoteViewsFactory$Stub.onTransact(IRemoteViewsFactory.java:49)
at android.os.Binder.execTransact(Binder.java:565)