-
Notifications
You must be signed in to change notification settings - Fork 206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace ugly runOnUiThreadIfFragmentAlive with Rx chain composition #42
Comments
Hi @artem-zinnatullin , could you explain your choice to not
Seems like a lot of extra work to defer the .post call to Also, shouldn't the |
Well, yeah, this is kind of thing I was not sure about when I initially Feel free to submit a PR to change it to observeOn(mainThread) where main On Wed, Apr 27, 2016 at 8:45 PM, Chris Zhang notifications@github.com
|
Soooooooo. Was fixing two What was the reason you would ask? Reason is simple, we have A LOT of rx streams, basically everything represented as rx streams, ui components like textview, buttons, etc are both streams and subscribers. And the problem is that for performance and shortness of the code we don't add Two possible solutions:
Just sharing my thoughts. |
All your Observables shouldn't end on UI but a data storage (behaviour subject, relay). Then, separately, subscribe those storages to the ui between resume and pause on the UI thread. Bam! no more threading issues. For intermediates use a functor operator to execute on specific schedulers (coming as a lib soonish). That also solves state persistence for configuration changes, and allows for out-of-lifecycle subscriptions. I've been evolving the architecture since last time we spoke, we need to catch up :D |
The thing is that we combine a lot of streams in ViewModels, like clicks with data change and so on, we simple don't have that "storage only" flow, all the logic of the UI described as Rx steams. |
Stateless dumb UI driven by business logic streams. You still get to call the showSnack, setAdapterElements, changeScreen (view or frag, pick your poison), listen for back key presses, request other activities for result, and that stuff... yet they're completely write once, then fire & forget. And because they're Definitely need to catch up. |
We will catch up :) Again, imagine all UI components are reactive, all clicks, text changes and so on. Then imagine how we work with them, we build combinations of those UI streams with data streams and then subscribe UI to the results, typical screen is about 10 combine(UI, data) streams on which we subscribe the UI so it displays what it should display. And that's when threading may go wrong. |
All reactive UI: https://github.com/pakoito/SongkickInterview/blob/master/app/src/main/java/com/pacoworks/dereference/screens/songkicklist/SongkickListActivity.java All reactive combinations: https://github.com/pakoito/SongkickInterview/blob/master/app/src/main/java/com/pacoworks/dereference/screens/songkicklist/SongkickListPresenter.java And that's from 7 months ago, it's evolved since. If you want to avoid the madness and get the persistence you'll have to go through the stores. |
Man, get yourself some lambdas! This looks similar to what we have, observeOn is not a great solution for the reasons I described above. Very easy to break or catch performance problems. |
It's not in the middle of the chain, no, that's why you want a proxy in the state stores instead of applying directly to UI. |
No dude, stay here as a man! Haha. I just think that somebody may find this useful, so let's keep it public. What if you need streams that will be used by another streams? Where would you apply scheduling?
|
This conversation definitely should keep public. I'm facing similar problem. How do you guys think about this idea: http://panavtec.me/say-goodbye-to-all-main-thread-problems-in-mvp? @artem-zinnatullin could you please share how you fix this problem with your real project? I'm really curious. |
Fixed with On Fri, May 6, 2016 at 3:43 PM, Thanh Le notifications@github.com wrote:
|
@pakoito , I'm looking at @artem-zinnatullin there is a danger to using observeOn(uiThread()) as detailed in this talk. I'm personally not sure of the best way to address this race condition, wrapping all my async observables in a BehaviorSubject doesn't sound fun. Maybe you can come up with a clever pattern! |
@cxzhang2 actually I don't see that race conditions actually. Handler posts actions one after another and if you won't try to reorder things manually I don't see much possibilities for the race conditions. |
@artem-zinnatullin Pierre-Yves Ricau blogged about it here. tldr: on your main looper:
|
I still don't see problem, if you unsubscribe from UI actions in onPause/onStop/onDestroy they will be removed from the Looper queue and no boom will happen. More over I don't see how any solution that I saw in similar discussions are different from posting to main Looper, they're just moving posting code from one layer to another and call it "solution for async peoblem". |
You are right that posting to a BehaviorSubject alone will not change anything, I think the (implied) idea behind those solutions is that the BehaviorSubject will live inside a singleton. It's essentially the same solution that @pakoito is suggesting, i.e. having a data layer that's not bound to the activity lifecycle in between your source observable and your UI subscription. Also, I was not aware that |
Basically you can do this with |
Good call, thanks! |
Ok, so I've deeply discussed this with team at Juno and we found really solid solution that solves 3 problems we have about
I hope we'll publish this as separate library and implement it in QualityMatters + blog post from me. |
@artem-zinnatullin I look forward to reading about it! |
So, here is the concept and implementation of the idea I was talking about: RxUi. Will implement it in qualitymatters in some ~near future. |
awesome @artem-zinnatullin. Reading it. |
If
View
methods returnAction1
or probablyObservable
/Single
will be able to compose them on the Presenter side and it'll work as part of initial chain.Though, I also see some drawbacks, but in general, it's more functional and clear approach -> 👍
// Thanks @pakoito for the input!
The text was updated successfully, but these errors were encountered: