Conversation
When Android kills the host process while a ScreenActivity is on the back stack and the user later returns, the OS recreates the activity before the host app has had a chance to call NoCodes.initialize again. AndroidX FragmentManager then reflectively reconstructs the saved ScreenFragment via its no-arg constructor, whose property initializers read DependenciesAssembly.instance - an uninitialized lateinit static - and the lateinit throws. Three layers of defense: - DependenciesAssembly exposes an isInstanceInitialized() helper so callers can check whether NoCodes.initialize has run in this process. - ScreenActivity installs a custom FragmentFactory before super.onCreate that returns a FinishingStubFragment in place of ScreenFragment when the assembly is uninitialized; the stub closes the activity and the host can re-show the screen after its own re-initialization. A defensive finish() handles the rare case where the saved state has no fragments, so the factory is never consulted. - ScreenFragment defers all DependenciesAssembly lookups via `by lazy` so its no-arg constructor is side-effect-free as defense in depth. Fixes qonversion/flutter-sdk#450 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9edb46b to
0e74ef3
Compare
SpertsyanKM
approved these changes
May 7, 2026
This was referenced May 7, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes qonversion/flutter-sdk#450.
ScreenActivityis restored by Android after process death (e.g., user kills the app from devtools while a no-codes screen is on the back stack and later relaunches). On restoration,super.onCreate(savedInstanceState)triggers AndroidXFragmentManager.restoreSaveState, which recreatesScreenFragmentvia reflection on the no-arg constructor.ScreenFragment's six property initializers readDependenciesAssembly.instance, which is set only byNoCodes.initialize- before the host app re-initializes (Flutter SDK can't realistically initialize beforeMainActivity.onCreate), the lateinit is unset and the read throwskotlin.UninitializedPropertyAccessException.Three layers of defense
DependenciesAssembly.isInstanceInitialized()- new helper on the companion that reports whether the lateinitinstancehas been assigned.ScreenActivity.onCreateguard - ifsavedInstanceState != nulland DI is not ready, strip both legacy (android:fragments) and modern (android:support:fragments) fragment-state keys, callsuper.onCreate(null), andfinish(). The host can re-show the screen after re-initialization.ScreenFragmentlazy DI lookups - all six DI-reading initializers (presenter,logger,delegateProvider,purchaseDelegateProvider,screenCustomizationDelegate,delegate) converted toby lazy.themeProviderwas already a deferred lambda. This keeps the no-arg constructor side-effect-free as defense-in-depth even if a future change forgets the activity guard.