SQLite - 数据库被锁定在"PRAGMA journal_mode" - 仅适用于某些Android设备的错误



Google Play预发布报告发现我的应用程序存在问题。此问题仅适用于少数设备。当我第一次尝试打开应用程序时,问题就会出现,而SQLite数据库是第一次打开的(在它被复制到设备之后(。该应用程序在首次事件后(第二次(正常打开。

事故发生在

mDatabase = SQLiteDatabase.openDatabase(mypath, null, SQLiteDatabase.OPEN_READWRITE);

创建数据库的代码:

/**
* 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){
}
}

我能够在模拟器上重现这个问题,详细的错误日志如下:

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)

谷歌Pixel 3设备的谷歌自动测试错误:

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)

感谢您对此的思考!

检查数据库是否关闭并打开它修复了问题:

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");
}
}
}

相关内容

最新更新