Zhuinden / realm-monarchy

[ACTIVE-ISH] A wrapper over Realm which exposes it as LiveData, managing Realm lifecycle internally.
Apache License 2.0
88 stars 11 forks source link

Warning when using Monarchy with a MediatorLiveData #9

Closed soulcramer closed 6 years ago

soulcramer commented 6 years ago

Hello! Thanks for building this library!

I have an issue when I switch rapidly from a Fragment to an another and come back to the first one I get java.lang.IllegalStateException: Handler (android.os.Handler) {8fa1de7} sending message to a Handler on a dead thread and observe on the current Livedata isn't called which doesn't refresh the screen.

I'm using the NetworkBoundResource class from the GithubBrowserSample and it's using a MediatorLiveData which under the hood is using observeForever on the source LiveData.

void plug() {
    mLiveData.observeForever(this);
}

I saw here and here in Monarchy that when the LiveData become inactive, there is an edge case and while debugging, I found out that the handler is effectively null when onInactive is called.


Here the stacktrace I get when I switch between fragments in my project:

2018-05-23 14:16:37.678 27892-27892/studio.lunabee.arn.debug W/MessageQueue: Handler (android.os.Handler) {8fa1de7} sending message to a Handler on a dead thread
    java.lang.IllegalStateException: Handler (android.os.Handler) {8fa1de7} sending message to a Handler on a dead thread
        at android.os.MessageQueue.enqueueMessage(MessageQueue.java:546)
        at android.os.Handler.enqueueMessage(Handler.java:745)
        at android.os.Handler.sendMessageAtTime(Handler.java:697)
        at android.os.Handler.sendMessageDelayed(Handler.java:667)
        at android.os.Handler.post(Handler.java:395)
        at com.zhuinden.monarchy.Monarchy.startListening(Monarchy.java:194)
        at com.zhuinden.monarchy.CopiedLiveResults.onActive(CopiedLiveResults.java:28)
        at android.arch.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:410)
        at android.arch.lifecycle.LiveData.observeForever(LiveData.java:207)
        at android.arch.lifecycle.MediatorLiveData$Source.plug(MediatorLiveData.java:141)
        at android.arch.lifecycle.MediatorLiveData.addSource(MediatorLiveData.java:96)
        at studio.lunabee.arn.repository.NetworkBoundResource$1.onChanged(NetworkBoundResource.kt:38)
        at android.arch.lifecycle.MediatorLiveData$Source.onChanged(MediatorLiveData.java:152)
        at android.arch.lifecycle.LiveData.considerNotify(LiveData.java:109)
        at android.arch.lifecycle.LiveData.dispatchingValue(LiveData.java:126)
        at android.arch.lifecycle.LiveData.setValue(LiveData.java:282)
        at android.arch.lifecycle.MutableLiveData.setValue(MutableLiveData.java:33)
        at android.arch.lifecycle.LiveData$1.run(LiveData.java:87)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6649)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:826)
Zhuinden commented 6 years ago

Oh man, that's kinda the race condition I feared could possibly happen between 0 -> 1 and 1 -> 0 where the handler thread is reinitialized.

Thanks for raising the issue.


What sucks is that I can think of two workarounds, neither of which I'm really fond of:

1.) have an observer that keeps the handler thread alive on activity-level

2.) i should just add a "start" / "stop" to monarchy where "start" starts up the handler thread, instead of managing its existence entirely based on active/inactive ref-counting, and that way we wouldn't have to worry about it being removed from under our feet on the ui thread. The Realm itself can be open-closed based on that, but the handler thread itself can clearly cause trouble...


Either way, this is pretty critical, so I'll think of it something today later when I get home.

Thanks again!

Zhuinden commented 6 years ago

Actually, one thing I noticed just now that compared to my other sample that I actually forgot both volatile or AtomicReference when I'm calling handler = null;.

How the hell did I miss that? 🙄 😞 I even handled it in my other sample?!

Either way, you might still need the handler thread to stop getting reinitialized when you're switching fragments, so that's a second thing for me to do. But first, time to fix the race...

Zhuinden commented 6 years ago

@soulcramer I have a potential fix for a very potential race condition with implementation 'com.github.Zhuinden:realm-monarchy:0.2.2' can you try if that's changed anything regarding posting to a dead thread?

soulcramer commented 6 years ago

@Zhuinden Thanks for your help, the warning and the bug is gone with this version!

Zhuinden commented 6 years ago

Happy to hear! :smile:

Thanks again for the report!