Practical Apps closed issue #5: App crashes at launch on older device at Practical Apps / HAMtrainer

Practical Apps
2021-05-23T04:31:17Z

An error occurs when attempting to launch the app on a motorolla droid 2 (Android 4.0.4). It appears that loading the main sql file into the database (Repository.java > onCreate) takes too long and the main menu (HamTrainerActivity.java > onResume) tries to load the exam topics (Repository.java > getTopicsCursor) before it has finished. The two simultaneous db transactions conflict and cause a crash. The following is the logcat output:

Collapsed output (Click to expand):
04/27 10:20:08: Launching 'app' on Motorola DROID2. $ adb shell am start -n "com.practicalapps.hamtrainer/com.practicalapps.hamtrainer.HamTrainerActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER Connected to process 3748 on device 'motorola-droid2-015DA5D01103601D'. Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page. V/ActivityThread: com.practicalapps.hamtrainer white listed for hwui I/SqliteDatabaseCpp: sqlite returned: error code = 1, msg = statement aborts at 2: [BEGIN;] cannot start a transaction within a transaction, db=/data/data/com.practicalapps.hamtrainer/databases/database_main_16.sql I/Funktrainer: Exception importing SQL file W/System.err: android.database.sqlite.SQLiteException: cannot start a transaction within a transaction W/System.err: at android.database.sqlite.SQLiteStatement.native_executeSql(Native Method) at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:90) at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1899) at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1839) at com.practicalapps.hamtrainer.data.Repository.importDatabaseFromSQLFile(Repository.java:108) at com.practicalapps.hamtrainer.data.Repository.onCreate(Repository.java:92) at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:165) at com.practicalapps.hamtrainer.data.Repository.getDb(Repository.java:156) at com.practicalapps.hamtrainer.data.Repository.setTopicsInSimpleCursorAdapter(Repository.java:576) at com.practicalapps.hamtrainer.HamTrainerActivity.onResume(HamTrainerActivity.java:168) at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1154) at android.app.Activity.performResume(Activity.java:4539) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2558) W/System.err: at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2596) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2110) at android.app.ActivityThread.access$600(ActivityThread.java:133) W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1158) at android.os.Handler.dispatchMessage(Handler.java:99) W/System.err: at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4609) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556) at dalvik.system.NativeStart.main(Native Method) I/SqliteDatabaseCpp: sqlite returned: error code = 1, msg = no such table: topic, db=/data/data/com.practicalapps.hamtrainer/databases/database_main_16.sql D/AndroidRuntime: Shutting down VM W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x40a511f8) E/AndroidRuntime: FATAL EXCEPTION: main java.lang.RuntimeException: Unable to resume activity {com.practicalapps.hamtrainer/com.practicalapps.hamtrainer.HamTrainerActivity}: android.database.sqlite.SQLiteException: no such table: topic: , while compiling: SELECT t._id AS _id, t.order_index AS order_index, t.name AS name, CASE WHEN MIN(level) >= 5 THEN ? ELSE SUM(CASE WHEN level < 5 THEN 1 ELSE 0 END) END AS status, MIN(CASE WHEN level >= 5 THEN NULL ELSE next_time END) AS next_question FROM topic t LEFT JOIN category_to_topic ct ON ct.topic_id = t._id LEFT JOIN question_to_category qt ON qt.category_id = ct.category_id LEFT JOIN question q ON q._id = qt.question_id GROUP BY t._id, t.order_index, t.name ORDER BY t.order_index at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2568) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2596) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2110) at android.app.ActivityThread.access$600(ActivityThread.java:133) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1158) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4609) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556) at dalvik.system.NativeStart.main(Native Method) Caused by: android.database.sqlite.SQLiteException: no such table: topic: , while compiling: SELECT t._id AS _id, t.order_index AS order_index, t.name AS name, CASE WHEN MIN(level) >= 5 THEN ? ELSE SUM(CASE WHEN level < 5 THEN 1 ELSE 0 END) END AS status, MIN(CASE WHEN level >= 5 THEN NULL ELSE next_time END) AS next_question FROM topic t LEFT JOIN category_to_topic ct ON ct.topic_id = t._id LEFT JOIN question_to_category qt ON qt.category_id = ct.category_id LEFT JOIN question q ON q._id = qt.question_id GROUP BY t._id, t.order_index, t.name ORDER BY t.order_index at android.database.sqlite.SQLiteCompiledSql.native_compile(Native Method) at android.database.sqlite.SQLiteCompiledSql.(SQLiteCompiledSql.java:68) at android.database.sqlite.SQLiteProgram.compileSql(SQLiteProgram.java:143) at android.database.sqlite.SQLiteProgram.compileAndbindAllArgs(SQLiteProgram.java:361) at android.database.sqlite.SQLiteProgram.(SQLiteProgram.java:127) at android.database.sqlite.SQLiteProgram.(SQLiteProgram.java:94) at android.database.sqlite.SQLiteQuery.(SQLiteQuery.java:53) at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:47) at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1564) at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1538) at com.practicalapps.hamtrainer.data.Repository.getTopicsCursor(Repository.java:582) at com.practicalapps.hamtrainer.data.Repository.setTopicsInSimpleCursorAdapter(Repository.java:576) at com.practicalapps.hamtrainer.HamTrainerActivity.onResume(HamTrainerActivity.java:168) at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1154) at android.app.Activity.performResume(Activity.java:4539) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2558) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2596) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2110) at android.app.ActivityThread.access$600(ActivityThread.java:133) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1158) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4609) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556) at dalvik.system.NativeStart.main(Native Method) Process 3748 terminated.

There are comments that have been preserved from the funktrainer source code that reference this issue (e.g. Repository.java line 90). In this comment a lock is suggested but not implemented. Simply placing objlock.lock()/unlock() around the calls in the same way as (HamTrainerActivity > setTopicsInSimpleCursorAdapter) does not seem to work. Simple waits at different locations have also been tried and do not to fix the problem.

This bug is not very impactful as it will only affect a small range of older and slower devices, but it is something that I feel should be solved. A solution seems like it should be simple but it is a bit beyond me. I'm looking for any help I can get on this issue that doesn't involve significant changes to the overall system.