diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt index bb452f37..ccf02785 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt @@ -61,7 +61,6 @@ class UApp : var setupDialogDisplayed = false override fun onCreate() { - initiated = true super.onCreate() if (BuildConfig.DEBUG) { @@ -70,6 +69,11 @@ class UApp : Timber.d("onCreate called") + // This flag flips once per install and NavigationActivity reads it while creating + // its UI, which can happen before the background initialization below completes. + // Reading it only on the main thread avoids serving a stale "false" on first run. + isFirstRun = Util.isFirstRun() + // In general we should not access the settings from the main thread to avoid blocking... ioScope.launch { if (Settings.debugLogToFile) { @@ -79,7 +83,6 @@ class UApp : // Populate externalFilesDir early FileUtil.cachedUltrasonicDirectory = FileUtil.ultrasonicDirectory Storage.mediaRoot.value - isFirstRun = Util.isFirstRun() } startKoin() @@ -113,6 +116,8 @@ class UApp : } internal fun startKoin() { + // "Koin is ready" is owned by startKoin alone; NavigationActivity relies on this + // flag to re-start Koin if the Application was recreated without a completed onCreate. initiated = true startKoin { // Sometimes Koin breaks when Kotlin version is upgraded, @@ -142,7 +147,10 @@ class UApp : companion object { var instance: UApp? = null - fun applicationContext(): Context = instance!!.applicationContext + fun applicationContext(): Context = + requireNotNull(instance) { + "UApp.instance accessed before Application.onCreate" + }.applicationContext } }