最近在使用Android 的GreenDao对数据库进行查询的操作时遇到了下面的异常:
android.database.sqlite.SQLiteCantOpenDatabaseException: unable to
open database file (code 14): , while compiling: PRAGMA journal_mode
详细异常的细节如下:
-05-25 11:04:30.845 26187-26219/com.pax.psp E/SQLiteLog: (14)
cannot open file at line 32460 of [8201f4e1c5] -05-25 11:04:30.845
26187-26219/com.pax.psp E/SQLiteLog: (14) os_unix.c:32460: (24)
open(/data/user/0/com.pax.psp/databases/data.db-journal) - -05-25
11:04:30.845 26187-26219/com.pax.psp E/SQLiteLog: (14) cannot open
file at line 32460 of [8201f4e1c5] -05-25 11:04:30.845
26187-26219/com.pax.psp E/SQLiteLog: (14) os_unix.c:32460: (24)
open(/data/user/0/com.pax.psp/databases/data.db-journal) - -05-25
11:04:30.845 26187-26219/com.pax.psp E/SQLiteLog: (14) unable to open
database file -05-25 11:04:30.899 26187-26219/com.pax.psp
E/SQLiteDatabase: Failed to open database
‘/data/user/0/com.pax.psp/databases/data.db’.
android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (code 14): , while compiling: PRAGMA journal_mode
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native
Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:634)
at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:320)
at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:294)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:738)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:296)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
at org.greenrobot.greendao.database.DatabaseOpenHelper.getWritableDb(DatabaseOpenHelper.java:59)
at com.pax.data.local.db.helper.DaoManager.getDatabase(DaoManager.java:47)
at com.pax.data.local.db.helper.DaoManager.getDaomaster(DaoManager.java:56)
at com.pax.data.local.db.helper.DaoManager.getDaoSession(DaoManager.java:60)
at com.pax.data.local.db.helper.BaseDaoHelper.getDaoSession(BaseDaoHelper.java:39)
at com.pax.data.local.db.helper.BaseDaoHelper.getDao(BaseDaoHelper.java:43)
at com.pax.data.local.db.helper.BaseDaoHelper.getNoSessionQuery(BaseDaoHelper.java:48)
at com.pax.data.local.db.helper.TransDataDbHelper.findOfflineTransData(TransDataDbHelper.java:95)
at com.pax.pay.service.OfflineSendService.offlineSend(OfflineSendService.java:62)
at com.pax.pay.service.OfflineSendService.access$000(OfflineSendService.java:38)
at com.pax.pay.service.OfflineSendService1.run(OfflineSendService.java:53)atjava.util.concurrent.Executors1.run(OfflineSendService.java:53) at java.util.concurrent.Executors1.run(OfflineSendService.java:53)atjava.util.concurrent.ExecutorsRunnableAdapter.call(Executors.java:428)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:278)
at java.util.concurrent.ScheduledThreadPoolExecutorScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:273)atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)atjava.util.concurrent.ThreadPoolExecutorScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:273) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutorScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:273)atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)atjava.util.concurrent.ThreadPoolExecutorWorker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761) -05-25 11:15:02.927 26187-26187/com.pax.psp E/InputChannel-JNI: Error 24 dup
channel fd 1023. -05-25 11:15:03.041 26187-26187/com.pax.psp
D/AndroidRuntime: Shutting down VM -05-25 11:15:03.139
26187-26187/com.pax.psp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.pax.psp, PID: 26187
java.lang.RuntimeException: Could not read input channel file descriptors from parcel.
at android.view.InputChannel.nativeReadFromParcel(Native Method)
at android.view.InputChannel.readFromParcel(InputChannel.java:148)
at android.view.InputChannel$1.createFromParcel(InputChannel.java:39)
at android.view.InputChannel$1.createFromParcel(InputChannel.java:37)
at com.android.internal.view.InputBindResult.(InputBindResult.java:68)
at com.android.internal.view.InputBindResult$1.createFromParcel(InputBindResult.java:112)
at com.android.internal.view.InputBindResult1.createFromParcel(InputBindResult.java:111)atcom.android.internal.view.IInputMethodManager1.createFromParcel(InputBindResult.java:111) at com.android.internal.view.IInputMethodManager1.createFromParcel(InputBindResult.java:111)atcom.android.internal.view.IInputMethodManagerStubProxy.startInputOrWindowGainedFocus(IInputMethodManager.java:710)atandroid.view.inputmethod.InputMethodManager.startInputInner(InputMethodManager.java:1258)atandroid.view.inputmethod.InputMethodManagerProxy.startInputOrWindowGainedFocus(IInputMethodManager.java:710) at android.view.inputmethod.InputMethodManager.startInputInner(InputMethodManager.java:1258) at android.view.inputmethod.InputMethodManagerProxy.startInputOrWindowGainedFocus(IInputMethodManager.java:710)atandroid.view.inputmethod.InputMethodManager.startInputInner(InputMethodManager.java:1258)atandroid.view.inputmethod.InputMethodManagerH.handleMessage(InputMethodManager.java:504)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6128)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
看了很多的博客,对上述异常有有如下的几种方案,结果跟我实际的情况都不相符。下面详细的分析一下具体的方案。
第一种方案:
可以参考:
/rainfall007/article/details/9454341?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
博客里面说是
data/data/应用的包名/databases文件夹不存在所以创建不了数据库。但是使用Device Explorer 查看数据库文件,发现存放数据库文件夹是存在的,并且数据库文件data.db也生成了。所以此方案对我的问题是不适用的。
第二种方案:
链接是:
/questions/34488306/unable-to-open-database-file-code-14-while-compiling-pragma-journal-mode
意思是:DatabaseHelper 的onCreate方法被调用两次,然后数据库锁住了。解决的方法把TableHelper的初始化TableHelper 的构造里面去掉。结果在自己的项目中打印日志没有发现onCreate 方法被调用多次。即使创建数据库表被调用了多次,数据库也不会被“锁住”。所以此方案也无法解决自己遇到的问题。
自己解决的办法:
最后在自己的OpenHelper的实现中发现OpenHelper对象每一次在创建的时候都是重新new了一个新的对象。在自己的业务的逻辑中,每隔10秒种都会从数据库中查询离线的交易记录。在查询数据库时,最后都调用了OpenHelper的构造重新生成了一个OpenHelper对象。后面自己尝试了写一段代码去验证,大约在counter 为475次时(即OpenHelper对象被创建了475次),程序就发生了崩溃。
while (true) {// offlineSend method is the database operation which will finally create OpenHelper object.offlineSend();counter++;LogUtils.e(TAG, "counter:" + counter);}
下面是Android Studio的Logcat 捕获的程序崩溃的异常的日志:
总结的原因是:Android SQLite数据库持有的OpenHelper的对象的数量是有限制的。解决的办法很简单,在创建OpenHelper之前加上判空的处理,避免重复创建新的OpenHelper对象。
private final DaoMaster.OpenHelper getHelper() {if (openHelper == null) {if (BuildConfig.DEBUG) {openHelper = new MySQLiteOpenHelper(FinancialApplication.getApp(), "data.db", null);} else {openHelper = new MyEncryptedSQLiteOpenHelper(FinancialApplication.getApp(), "data.db", null);}}return openHelper;}
后记
每天进步一点点。希望有一天可以把这些点滴穿起来,未来有一天回忆起来的时候,会记得那么一些。留下一些东西给自己,也给别人。“人生到处知何似,应是飞鸿踏雪泥。”