airbnb / mavericks

Mavericks: Android on Autopilot
https://airbnb.io/mavericks/
Apache License 2.0
5.85k stars 499 forks source link

Fix lifecycle 2.3.0 throwing IllegalStateException when using `MavericksLauncherActivity` #523

Closed marukami closed 3 years ago

marukami commented 3 years ago

lifecycle#2.3.0 throws IllegalStateException if the addObserver is invoked outside of the main thread.

As per the suggestion in the change notes I added a synchronized block and use createUnsafe.

I edited the helloDagger module to demo the error and you get the crash once you try opening the HelloFragment after launching the MavericksLauncherActivity. I did using the adb shell.

adb shell am start -n com.airbnb.mvrx.helloDagger/com.airbnb.mvrx.launcher.MavericksLauncherActivity

I left the demo code in this PR to make checking before/after the change easier. I'm actually not sure how to add a test for this outside of a manual check.

java.lang.IllegalStateException: Method addObserver must be called on the main thread
        at androidx.lifecycle.LifecycleRegistry.enforceMainThreadIfNeeded(LifecycleRegistry.java:317)
        at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:172)
        at com.airbnb.mvrx.lifecycleAwareLazy.observerLifecycle(lifecycleAwareLazy.kt:40)
        at com.airbnb.mvrx.lifecycleAwareLazy.<init>(lifecycleAwareLazy.kt:36)
        at com.airbnb.mvrx.mocking.MockViewModelDelegateFactory.createLazyViewModel(MockViewModelDelegateFactory.kt:58)
        at com.airbnb.mvrx.hellodagger.HelloFragment$$special$$inlined$fragmentViewModel$2.provideDelegate(ViewModelDelegateProvider.kt:23)
        at com.airbnb.mvrx.hellodagger.HelloFragment$$special$$inlined$fragmentViewModel$2.provideDelegate(ViewModelDelegateProvider.kt:17)
        at com.airbnb.mvrx.hellodagger.HelloFragment.<init>(HelloFragment.kt:57)
        at java.lang.Class.newInstance(Native Method)
        at com.airbnb.mvrx.mocking.ViewMockerKt$getMockVariants$2.invoke(ViewMocker.kt:87)
        at com.airbnb.mvrx.mocking.ViewMockerKt$getMockVariants$2.invoke(Unknown Source:4)
        at com.airbnb.mvrx.mocking.ViewMockerKt$getMockVariants$3.invoke(ViewMocker.kt:96)
        at com.airbnb.mvrx.mocking.ViewMockerKt$getMockVariants$3.invoke(Unknown Source:4)
        at com.airbnb.mvrx.mocking.ViewMockerKt.getMockVariants(ViewMocker.kt:126)
        at com.airbnb.mvrx.mocking.ViewMockerKt.getMockVariants(ViewMocker.kt:94)
        at com.airbnb.mvrx.mocking.ViewMockerKt.getMockVariants$default(ViewMocker.kt:92)
        at com.airbnb.mvrx.launcher.MavericksLauncherFragment.getMocksForSelectedView(MavericksLauncherFragment.kt:91)
        at com.airbnb.mvrx.launcher.MavericksLauncherFragment.access$getMocksForSelectedView$p(MavericksLauncherFragment.kt:34)
        at com.airbnb.mvrx.launcher.MavericksLauncherFragment$epoxyController$1.invoke(MavericksLauncherFragment.kt:141)
        at com.airbnb.mvrx.launcher.MavericksLauncherFragment$epoxyController$1.invoke(MavericksLauncherFragment.kt:34)
        at com.airbnb.mvrx.launcher.MavericksEpoxyControllerKt$simpleController$2$1.invoke(MavericksEpoxyController.kt:47)
        at com.airbnb.mvrx.launcher.MavericksEpoxyControllerKt$simpleController$2$1.invoke(Unknown Source:2)
        at com.airbnb.mvrx.StateContainerKt.withState(StateContainer.kt:6)
        at com.airbnb.mvrx.launcher.MavericksEpoxyControllerKt$simpleController$2.invoke(MavericksEpoxyController.kt:46)
        at com.airbnb.mvrx.launcher.MavericksEpoxyControllerKt$simpleController$2.invoke(Unknown Source:2)
        at com.airbnb.mvrx.launcher.MavericksEpoxyController.buildModels(MavericksEpoxyController.kt:21)
        at com.airbnb.epoxy.EpoxyController$1.run(EpoxyController.java:281)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.os.HandlerThread.run(HandlerThread.java:67)