[英]SQLite - database is locked in "PRAGMA journal_mode" - error only for certain Android devices
Google Play pre-launch report found an issue with my app. Google Play 预发布报告发现我的应用存在问题。 This issue comes up only for a few devices.
此问题仅针对少数设备出现。 The problem occurs when I try to open the app for the first time, and the SQLite database is being opened for the first time (after it was copied to the device).
当我第一次尝试打开应用程序时出现问题,并且第一次打开 SQLite 数据库(在将其复制到设备之后)。 The app opens fine after this initial incident (for the second time).
该应用程序在此初始事件后(第二次)正常打开。
The crash happens at line:崩溃发生在:
mDatabase = SQLiteDatabase.openDatabase(mypath, null, SQLiteDatabase.OPEN_READWRITE);
The code for the database creation:创建数据库的代码:
/**
* constructor should be private to prevent direct instantiation.
* make call to static factory method "getInstance()" instead.
*/
private DbHelper(Context context) throws SQLException, IOException {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
DB_PATH = Environment.getDataDirectory() + "/data/" + context.getPackageName() + "/databases/";
helperContext = context;
boolean dbexist = checkdatabase();
if (dbexist) {
open();
} else {
createdatabase();
}
}
public void createdatabase() throws IOException {
boolean dbexist = checkdatabase();
if(!dbexist) {
// By calling this method and empty database will be created into
// the default system path
// of your application so we are gonna be able to overwrite that
// database with our database.
this.getReadableDatabase();
this.close();
try {
copydatabase();
this.getReadableDatabase();
} catch(IOException e) {
throw new Error("Error copying database");
}
}
}
private boolean checkdatabase() {
boolean checkdb = false;
try {
String myPath = DB_PATH + DATABASE_NAME;
File dbfile = new File(myPath);
checkdb = dbfile.exists();
} catch (SQLiteException e) {
System.out.println("Database doesn't exist");
}
return checkdb;
}
private void copydatabase() throws IOException {
//Open your local db as the input stream
InputStream myinput = helperContext.getAssets().open(DATABASE_NAME);
// Path to the just created empty db
String outfilename = DB_PATH + DATABASE_NAME;
//Open the empty db as the output stream
OutputStream myoutput = new FileOutputStream(outfilename);
// transfer byte to inputfile to outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myinput.read(buffer)) > 0) {
myoutput.write(buffer, 0, length);
}
//Close the streams
myoutput.flush();
myoutput.close();
myinput.close();
}
public void open() throws SQLException {
//Open the database
String mypath = DB_PATH + DATABASE_NAME;
mDatabase = SQLiteDatabase.openDatabase(mypath, null, SQLiteDatabase.OPEN_READWRITE);
}
public synchronized void close() {
if (mDatabase != null) {
mDatabase.close();
}
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
mDatabase = db;
try {
this.createdatabase();
open();
}catch(Exception ex){
}
}
I was able to reproduce this issue on a simulator, the detailed error log is below:我能够在模拟器上重现这个问题,详细的错误日志如下:
E/SQLiteLog: (5) database is locked in "PRAGMA journal_mode"
E/SQLiteDatabase: Failed to open database '/data/data/com.ch.mo/databases/moDB.db'.
android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5 SQLITE_BUSY): , while compiling: PRAGMA journal_mode
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1045)
at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:788)
at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:405)
at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:345)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:258)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:205)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:505)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:206)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:198)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:918)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:898)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:789)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:736)
at com.ch.mo.DbHelper.open(DbHelper.java:128)
at com.ch.mo.DbHelper.onCreate(DbHelper.java:143)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:411)
at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:340)
at com.ch.mo.DbHelper.createdatabase(DbHelper.java:79)
at com.ch.mo.DbHelper.<init>(DbHelper.java:67)
at com.ch.mo.DbHelper.getInstance(DbHelper.java:46)
at com.ch.mo.MainActivity.onCreate(MainActivity.java:573)
at android.app.Activity.performCreate(Activity.java:7994)
at android.app.Activity.performCreate(Activity.java:7978)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
D/CompatibilityChangeReporter: Compat change id reported: 147798919; UID 10121; state: ENABLED
D/HostConnection: HostConnection::get() New Host Connection established 0xf4be3390, tid 3464
D/HostConnection: HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_native_sync_v2 ANDROID_EMU_native_sync_v3 ANDROID_EMU_native_sync_v4 ANDROID_EMU_dma_v1 ANDROID_EMU_direct_mem ANDROID_EMU_host_composition_v1 ANDROID_EMU_host_composition_v2 ANDROID_EMU_vulkan ANDROID_EMU_deferred_vulkan_commands ANDROID_EMU_vulkan_null_optional_strings ANDROID_EMU_vulkan_create_resources_with_requirements ANDROID_EMU_YUV_Cache ANDROID_EMU_vulkan_ignored_handles ANDROID_EMU_has_shared_slots_host_memory_allocator ANDROID_EMU_vulkan_free_memory_sync ANDROID_EMU_vulkan_shader_float16_int8 ANDROID_EMU_vulkan_async_queue_submit ANDROID_EMU_sync_buffer_data ANDROID_EMU_read_color_buffer_dma GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_host_side_tracing ANDROID_EMU_gles_max_version_2
W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
D/EGL_emulation: eglCreateContext: 0xf4bcd4b0: maj 2 min 0 rcv 2
D/EGL_emulation: eglMakeCurrent: 0xf4bcd4b0: ver 2 0 (tinfo 0xf4f2e4b0) (first time)
I/Gralloc4: mapper 4.x is not supported
D/HostConnection: createUnique: call
HostConnection::get() New Host Connection established 0xf4bd52b0, tid 3464
D/goldfish-address-space: allocate: Ask for block of size 0x100
D/goldfish-address-space: allocate: ioctl allocate returned offset 0x3f3ffe000 size 0x2000
D/HostConnection: HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_native_sync_v2 ANDROID_EMU_native_sync_v3 ANDROID_EMU_native_sync_v4 ANDROID_EMU_dma_v1 ANDROID_EMU_direct_mem ANDROID_EMU_host_composition_v1 ANDROID_EMU_host_composition_v2 ANDROID_EMU_vulkan ANDROID_EMU_deferred_vulkan_commands ANDROID_EMU_vulkan_null_optional_strings ANDROID_EMU_vulkan_create_resources_with_requirements ANDROID_EMU_YUV_Cache ANDROID_EMU_vulkan_ignored_handles ANDROID_EMU_has_shared_slots_host_memory_allocator ANDROID_EMU_vulkan_free_memory_sync ANDROID_EMU_vulkan_shader_float16_int8 ANDROID_EMU_vulkan_async_queue_submit ANDROID_EMU_sync_buffer_data ANDROID_EMU_read_color_buffer_dma GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_host_side_tracing ANDROID_EMU_gles_max_version_2
D/AndroidRuntime: Shutting down VM
--------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ch.mo, PID: 3434
java.lang.IllegalStateException: Fragment already added: Songs{e0fd133} (8c0858e6-ae0b-4903-9f34-c790c433860b) id=0x7f08022b android:switcher:2131231275:0}
at androidx.fragment.app.FragmentStore.addFragment(FragmentStore.java:67)
at androidx.fragment.app.FragmentManager.addFragment(FragmentManager.java:1563)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:405)
at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2167)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1990)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1945)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847)
at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
The error from the Google automatic test for Google Pixel 3 device: Google Pixel 3 设备的 Google 自动测试错误:
FATAL EXCEPTION: main
Process: com.ch.mo, PID: 20970
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ch.mo/com.ch.mo.MainActivity}: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.ch.mo/databases/moDB.db
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2951)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3086)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1816)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.ch.mo/databases/moDB.db
at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1404)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1347)
at com.ch.mo.MainActivity.w(:1)
at com.ch.mo.MainActivity.onCreate(:2)
at android.app.Activity.performCreate(Activity.java:7144)
at android.app.Activity.performCreate(Activity.java:7135)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2931)
Thanks for your thoughts on this!感谢您对此的想法!
Checking if the database is closed, and opening it fixed the issue:检查数据库是否关闭,然后打开它解决了问题:
public void createdatabase() throws SQLException, IOException {
boolean dbexist = checkdatabase();
if(!dbexist) {
// By calling this method and empty database will be created into
// the default system path
// of your application so we are gonna be able to overwrite that
// database with our database.
if (mDatabase != null && !mDatabase.isOpen())
this.open();
this.getReadableDatabase();
this.close();
try {
copydatabase();
this.getReadableDatabase();
if (mDatabase != null && !mDatabase.isOpen())
this.open();
} catch(IOException e) {
throw e;//new Error("Error copying database");
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.