russhwolf / multiplatform-settings

A Kotlin Multiplatform library for saving simple key-value data
Apache License 2.0
1.49k stars 64 forks source link

After update to 1.0.0, Its crashing on Android. working fine on iOS #166

Open vinod6124 opened 10 months ago

vinod6124 commented 10 months ago
FATAL EXCEPTION: main
                                       Process: com.easemytrip.android, PID: 6341
                                       java.lang.ExceptionInInitializerError
                                        at com.easemytrip.android.SplashActivity.onCreate(SplashScreenActivity.kt:111)
                                        at android.app.Activity.performCreate(Activity.java:8290)
                                        at android.app.Activity.performCreate(Activity.java:8269)
                                        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384)
                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3657)
                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813)
                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
                                        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:2308)
                                        at android.os.Handler.dispatchMessage(Handler.java:106)
                                        at android.os.Looper.loopOnce(Looper.java:201)
                                        at android.os.Looper.loop(Looper.java:288)
                                        at android.app.ActivityThread.main(ActivityThread.java:7898)
                                        at java.lang.reflect.Method.invoke(Native Method)
                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
                                       Caused by: java.lang.NullPointerException
                                        at `com.russhwolf.settings.NoArgKt.Settings(NoArg.kt:32)`
                                        at com.easemytrip.shared.utils.MySettings.<clinit>(EmtSettings.kt:8)
                                        at com.easemytrip.android.SplashActivity.onCreate(SplashScreenActivity.kt:111) 
                                        at android.app.Activity.performCreate(Activity.java:8290) 
                                        at android.app.Activity.performCreate(Activity.java:8269) 
                                        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384) 
                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3657) 
                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813) 
                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) 
                                        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:2308) 
                                        at android.os.Handler.dispatchMessage(Handler.java:106) 
                                        at android.os.Looper.loopOnce(Looper.java:201) 
                                        at android.os.Looper.loop(Looper.java:288) 
                                        at android.app.ActivityThread.main(ActivityThread.java:7898) 
                                        at java.lang.reflect.Method.invoke(Native Method) 
                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) 
                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936) 
russhwolf commented 10 months ago

I see android.app.Instrumentation.callActivityOnCreate() in your stack trace. Is this happening in a Robolectric test? If so, then this might be the same issue as #127

vinod6124 commented 10 months ago

@russhwolf No, I am running the build in release mode. Using it for 2 years but first time I've had such an issue. Is there any extra workaround for this I'm not able to figure out?

Crash line: val settings: Settings = Settings() commonMain Gradle: implementation("com.russhwolf:multiplatform-settings-no-arg:1.0.0")

ahna92 commented 10 months ago

hi @russhwolf We face this issue with 1.0.0-RC too when calling the settings at a process that is not the application main process (service process)

such as Application.onCreate()

MyApplication extends Application {

  override fun onCreate {
    // getSettings() <---- access settings here result into a crash 
    if (isMainProcess()){
       // getSettings() <----  access settings here does not cause a crash 
    }
  }

  private fun isMainProcess(): Boolean {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
          return packageName == processName
      }
      return packageName == getProcessNameLegacy()
  }

  // You can use this method to get the current process name
  private fun getProcessNameLegacy(): String? {
      try {
          val mypid = android.os.Process.myPid()
          val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
          val infos = manager.runningAppProcesses
          for (info in infos) {
              if (info.pid == mypid) {
                  return info.processName
              }
          }
      } catch (e: Exception) {
          // Handle the exception if needed
      }
      // May never return null
      return null
  }
}

same goes for koin because koin is called at Application.onCreate() and if settings were access during the startKoin function and it's not the main process the crash happen

russhwolf commented 10 months ago

@vinod6124 I've never seen this issue before, but one workaround would be to manually inject your Settings instance per-platform rather than using no-arg.

@ahna92 I'm not clear whether your issue is the same one as was originally reported here or not. But in any case SharedPreferences doesn't support usage across multiple processes. I'm not sure why you're crashing, vs just getting inconsistent data returned, but I don't expect what you're doing to work generally.

ahna92 commented 10 months ago

@russhwolf i'll share stack trace below ,

SharedPreferences inconsistent data is not a big concern for my case , since i'm only using the library in the main process (mostly UI related)

but i mentioned the multi process bc the crash did stoped happing when only invoking the lib in main process maybe it's not the root cause but it's related ,

I just noticed the android.app.Instrumentation.callApplicationOnCreate not sure why it's under Instrumentation.* but i'm getting the crashing from real production devices

Caused by java.lang.NullPointerException:
       at com.russhwolf.settings.NoArgKt.Settings(NoArg.kt:32)
       at io.telereso.kmp.core.SettingsImpl.<init>(Settings.kt:217)
       at io.telereso.kmp.core.Settings$Companion.get-BwNAW2A(Settings.kt:46)
       at io.telereso.kmp.core.Settings$Companion.get-BwNAW2A$default(Settings.kt:45)
       at com.airasia.sso.client.PlatformKt.<clinit>(Platform.kt:48)
       at com.airasia.sso.client.PlatformKt.getSettings(Platform.kt:48)
       at com.airasia.sso.client.SsoClientManager$settingsManager$2.invoke(SsoClientManager.kt:100)
       at com.airasia.sso.client.SsoClientManager$settingsManager$2.invoke(SsoClientManager.kt:99)
       at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
       at com.airasia.sso.client.SsoClientManager.getSettingsManager(SsoClientManager.kt:99)
       at com.airasia.sso.client.SsoClientManager.<init>(SsoClientManager.kt:246)
       at com.airasia.sso.client.SsoClientManager.<init>(SsoClientManager.kt:269)
       at com.airasia.sso.client.SsoClientManager$Builder.build(SsoClientManager.kt:828)
       at com.airasia.di.ModulesKt$applicationModule$1$12.invoke(Modules.kt:117)
       at com.airasia.di.ModulesKt$applicationModule$1$12.invoke(Modules.kt:113)
       at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
       at org.koin.core.instance.SingleInstanceFactory.create(SingleInstanceFactory.kt:46)
       at org.koin.core.instance.SingleInstanceFactory$get$1.invoke(SingleInstanceFactory.kt:53)
       at org.koin.core.instance.SingleInstanceFactory$get$1.invoke(SingleInstanceFactory.kt:51)
       at org.koin.mp.KoinPlatformTools.synchronized(PlatformToolsJVM.kt:20)
       at org.koin.core.instance.SingleInstanceFactory.get(SingleInstanceFactory.kt:51)
       at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
       at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
       at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
       at org.koin.core.scope.Scope.get(Scope.kt:204)
       at org.koin.core.Koin.get(Koin.kt:130)
       at org.koin.java.KoinJavaComponent.get(KoinJavaComponent.kt:87)
       at org.koin.java.KoinJavaComponent.get$default(KoinJavaComponent.kt:81)
       at com.airasia.util.GlobalApplicationHelper.setUpSsoManagerBridge(GlobalApplicationHelper.kt:409)
       at com.airasia.mobile.GlobalApplication.onCreate(GlobalApplication.java:224)
       at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1285)
       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7231)
       at android.app.ActivityThread.-$$Nest$mhandleBindApplication()
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2288)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loopOnce(Looper.java:240)
       at android.os.Looper.loop(Looper.java:351)
       at android.app.ActivityThread.main(ActivityThread.java:8381)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013)
russhwolf commented 8 months ago

I don't think 1.1.0 will have solved this issue (I'm still not sure what's going on here), but try upgrading if you get a chance and let me know if we got lucky.

russhwolf commented 8 months ago

For folks who are experiencing this issue, are you using androidx.startup elsewhere in your app? If so what version? Are you doing any customization in your AndroidManifest of when initializers are run, such as the sort of config described here?

aprokofjev-mwb commented 7 months ago

@russhwolf I'm using android.startup with version 1.1.1 and getting the same issue as described above if I add custom initializer (not in tests). In my case crash happens because my custom initializer should depend on com.russhwolf.settings.SettingsInitializer but since this class is internal I can't do it :( It would be great if the SettingsInitializer became public

russhwolf commented 5 months ago

I'm planning to make SettingsInitializer public in version 1.2. That will add some flexibility if you're doing custom androidx.startup initialization. I'm not clear whether or not that accounts for all the issues reported in this thread, so I'd still like to hear whether folks who are having issues are using custom initialization or not.