multiplatform-settings
multiplatform-settings copied to clipboard
[Android] Nullpointer exception while creating Settings instance
We are receiving crash while creating instance of Settings on Android. Looks its not able to get context from androidx-startup ? version: 0.8
Caused by java.lang.NullPointerException
at com.russhwolf.settings.NoArgKt.Settings(NoArgKt.java:33)
Seems weird, but that doesn't really give me enough information to understand what's going on. Since 0.8 is pretty old, can you try it on a newer version such as 1.0.0-alpha01?
@russhwolf regarding the issue raised, i have a kmm app that i try to test with robolectric from android module (android/src/test). I wanna test the Main Activity but even the simplest test like assertNotNull(activity) crashes with the same error. I have upgraded to latest version 1.0.0-alpha01.
And the stack trace below
java.lang.NullPointerException at com.russhwolf.settings.NoArgKt.Settings(NoArg.kt:32) at com.calendrop.app.service.SettingsRepository$Companion$instance$2.invoke(SettingsRepository.kt:11) at com.calendrop.app.service.SettingsRepository$Companion$instance$2.invoke(SettingsRepository.kt:10) at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) at com.calendrop.app.service.SettingsRepository$Companion.getInstance(SettingsRepository.kt:10) at com.calendrop.common.ui.viewmodel.LanguageSettings.
(LanguageSettings.kt:27) at com.calendrop.common.ui.viewmodel.LanguageSettings$Companion.getInstance(LanguageSettings.kt:21) at com.calendrop.common.ui.utils.GetResourcesKt.SetStoredLanguage(GetResources.kt:49) at com.calendrop.common.ui.utils.GetResourcesKt.SetupApplicationLanguage(GetResources.kt:44) at com.calendrop.common.ui.SplashScreenUINewKt.SplashScreenContentNew(SplashScreenUINew.kt:25) at com.calendrop.common.ui.utils.RootUIKt$SplashContentNew$1.invoke(RootUI.kt:50) at com.calendrop.common.ui.utils.RootUIKt$SplashContentNew$1.invoke(RootUI.kt:48) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.ChildrenKt$Children$1$1.invoke(Children.kt:31) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.ChildrenKt$Children$1$1.invoke(Children.kt:30) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228) at androidx.compose.runtime.saveable.SaveableStateHolderImpl.SaveableStateProvider(SaveableStateHolder.kt:84) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.ChildrenKt$Children$1.invoke(Children.kt:30) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.ChildrenKt$Children$1.invoke(Children.kt:29) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.DefaultStackAnimation$invoke$1$1$2.invoke(DefaultStackAnimation.kt:55) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.DefaultStackAnimation$invoke$1$1$2.invoke(DefaultStackAnimation.kt:53) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.ComposableSingletons$FadeKt$lambda-1$1.invoke(Fade.kt:17) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.ComposableSingletons$FadeKt$lambda-1$1.invoke(Fade.kt:16) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:149) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.DefaultStackAnimator.invoke(DefaultStackAnimator.kt:43) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.DefaultStackAnimation.invoke(DefaultStackAnimation.kt:42) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.ChildrenKt.Children(Children.kt:29) at com.arkivanov.decompose.extensions.compose.jetbrains.stack.ChildrenKt.Children(Children.kt:46) at com.calendrop.common.ui.utils.RootUIKt.SplashContentNew(RootUI.kt:45) at com.calendrop.android.MainActivity$onCreate$1$1.invoke(MainActivity.kt:33) at com.calendrop.android.MainActivity$onCreate$1$1.invoke(MainActivity.kt:32) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at com.calendrop.app.theme.AppThemeKt$AppTheme$1.invoke(AppTheme.kt:40) at com.calendrop.app.theme.AppThemeKt$AppTheme$1.invoke(AppTheme.kt:39) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228) at com.calendrop.app.theme.AppThemeKt.AppTheme(AppTheme.kt:33) at com.calendrop.android.MainActivity$onCreate$1.invoke(MainActivity.kt:32) at com.calendrop.android.MainActivity$onCreate$1.invoke(MainActivity.kt:27) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.ui.platform.ComposeView.Content(ComposeView.android.kt:404) at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:250) at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:249) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228) at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:177) at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:123) at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:122) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228) at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.ProvideAndroidCompositionLocals(AndroidCompositionLocals.android.kt:114) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:157) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:156) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:156) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:140) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:78) at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3248) at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3238) at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341) at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source) at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3238) at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3173) at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:587) at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:950) at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:519) at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:140) at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:131) at androidx.compose.ui.platform.AndroidComposeView.setOnViewTreeOwnersAvailable(AndroidComposeView.android.kt:1060) at androidx.compose.ui.platform.WrappedComposition.setContent(Wrapper.android.kt:131) at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Wrapper.android.kt:182) at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:360) at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:202) at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:138) at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:131) at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.android.kt:1147) at android.view.View.dispatchAttachedToWindow(View.java:20753) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3490) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3497) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2613) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2126) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8649) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1037) at android.view.Choreographer.doCallbacks(Choreographer.java:845) at android.view.Choreographer.doFrame(Choreographer.java:780) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1022) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at org.robolectric.shadows.ShadowPausedLooper$IdlingRunnable.run(ShadowPausedLooper.java:368) at org.robolectric.shadows.ShadowPausedLooper.executeOnLooper(ShadowPausedLooper.java:402) at org.robolectric.shadows.ShadowPausedLooper.idle(ShadowPausedLooper.java:93) at org.robolectric.shadows.ShadowPausedLooper.idleIfPaused(ShadowPausedLooper.java:164) at org.robolectric.android.controller.ActivityController.visible(ActivityController.java:208) at org.robolectric.android.controller.ActivityController.setup(ActivityController.java:319) at com.calendrop.android.TestApplication.setUp(TestApplication.kt:47) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) at org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:54) at androidx.compose.ui.test.junit4.AndroidComposeTestRule$apply$1$evaluate$1.invoke(AndroidComposeTestRule.android.kt:148) at androidx.compose.ui.test.junit4.AndroidComposeTestRule$apply$1$evaluate$1.invoke(AndroidComposeTestRule.android.kt:147) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$AndroidComposeUiTestImpl.withDisposableContent(ComposeUiTest.android.kt:476) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1$1$1$1$1.invoke(ComposeUiTest.android.kt:294) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.withTextInputService(ComposeUiTest.android.kt:360) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.access$withTextInputService(ComposeUiTest.android.kt:217) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1$1$1$1.invoke(ComposeUiTest.android.kt:293) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.withComposeIdlingResource(ComposeUiTest.android.kt:347) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.access$withComposeIdlingResource(ComposeUiTest.android.kt:217) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1$1$1.invoke(ComposeUiTest.android.kt:292) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.withWindowRecomposer(ComposeUiTest.android.kt:321) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.access$withWindowRecomposer(ComposeUiTest.android.kt:217) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1$1.invoke(ComposeUiTest.android.kt:291) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.withTestCoroutines(ComposeUiTest.android.kt:334) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.access$withTestCoroutines(ComposeUiTest.android.kt:217) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1.invoke(ComposeUiTest.android.kt:290) at androidx.compose.ui.test.junit4.IdlingStrategy.withStrategy(IdlingStrategy.android.kt:52) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1.invoke(ComposeUiTest.android.kt:289) at androidx.compose.ui.test.junit4.IdlingResourceRegistry.withRegistry(IdlingResourceRegistry.jvm.kt:157) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1.invoke(ComposeUiTest.android.kt:288) at androidx.compose.ui.test.junit4.ComposeRootRegistry.withRegistry(ComposeRootRegistry.android.kt:146) at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.runTest(ComposeUiTest.android.kt:287) at androidx.compose.ui.test.junit4.AndroidComposeTestRule$apply$1.evaluate(AndroidComposeTestRule.android.kt:147) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:591) at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:274) at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:88) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829)
I don't think androidx.startup gets initialized in a Robolectric test. There's not really much Multiplatform Settings can do there.
I could think about adding an API where you could inject your test Context
the way the library does in its tests. But if you're going to use something like that, you might as well just inject the Settings
instance instead and avoid calling the no-arg constructor from your tests in the first place.
I have the same issue, and I've tried the new 1.0.0-RC version but unsuccessfully.
Same here, the merged manifest seems ok, the androidx.startup.InitializationProvider
and com.russhwolf.settings.SettingsInitializer
is there, but it appears the SettingsInitializer
isn't receiving the context.
I'm using 1.0.0
FATAL EXCEPTION: main
Process: com.stone.tapsdk:TLniWnlh6DxccKfljv7c, PID: 25927
java.lang.RuntimeException: Unable to create application com.example.app.DemoApplication: java.lang.NullPointerException
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7000)
at android.app.ActivityThread.access$1500(ActivityThread.java:258)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1983)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:236)
at android.app.ActivityThread.main(ActivityThread.java:8061)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
Caused by: java.lang.NullPointerException
at com.russhwolf.settings.NoArgKt.Settings(NoArg.kt:32)
at co.stone.commons.InitiatorTransactionKeyHandler.<init>(InitiatorTransactionKeyHandler.kt:9)
at com.example.lib.TapPciMpp.<init>(TapPciMpp.kt:41)
at com.example.lib.TapSdk.selectLib(TapSdk.kt:20)
at com.example.lib.TapSdk.initialize(TapSdk.kt:27)
at com.example.app.DemoApplication.onCreate(DemoApplication.kt:9)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1193)
Again, I don't expect this to work from a Robolectric test because I don't think Robolectric correctly initializes ContentProviders like androidx.startup uses. If you need to test code that talks to your Settings
object, pass in a MapSettings
instead of calling the no-arg
constructor.
I had the same issue in my app with multiple processes, so I fixed it with an explicit call of the library initializer in my Application
class implementation:
AppInitializer.getInstance(getApplicationContext()).initializeComponent(SettingsInitializer.class);
Oh that's interesting. SettingsInitializer
is marked internal
, so that only works from Java code, but maybe the right solution here is to just make it public.
I plan to make SettingsInitializer
public in version 1.2.0 so that you have more flexibility to handle this in tests.