-
Notifications
You must be signed in to change notification settings - Fork 990
Refactor Discovery to properly recover from stopped processes #48
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
Conversation
Pass along the root categories from the activity instead, via the pagerAdapter.
…eChanged -> pageSelected
This should fix a bug where restoring the first discovery page after the app has been stopped (not killed) results in a blank page. The previous approach used `pagerCreatedPage` and `pageSelections`. Unfortunately we can't rely entirely on `pageSelections` since it will emit page 0 on subscribe, even if a different page is eventually restored. `pagerCreatedPage` is also problematic because the fragment manager may not *create* the fragment instance again on reload; the fragment instance persists and we never get the create event. It seems like the best tool available to figure out when a page is ready to receive params is to hook into `setPrimaryItem` events. It fires many times, so we use `distinctUntilChanged` to de-dupe. The one last wrinkle is that it seems like a fragment may not be ready to receive params immediately after `setPrimaryItem` is called – I've hooked up a delay so that execution here is deferred until the next run loop. It's pretty janky and maybe we could spend more time thinking about it since it's not a great pattern.
…or Fragment creation delay
👏 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fab, nice and clean PR thanks to the refactor in #44.
@@ -176,6 +176,9 @@ private Transformers() {} | |||
/** | |||
* If called on the main thread, schedule the work immediately. Otherwise delay execution of the work by adding it | |||
* to a message queue, where it will be executed on the main thread. | |||
* | |||
* This is useful for `RecyclerView`s where new data can appear immediately rather than waiting for a frame |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might slightly rephrase this –
This is particularly useful for
RecyclerView
s; if subscriptions in these views are delayed for a frame, then the views temporarily shows recycled content and frame rate stutters. To address that, we can useobserveForUI
to execute the work immediately rather than wait for a frame.
PR 230 in the old repo goes into more detail.
what
When an app goes into the background for a while, the Android system reclaims memory by stopping idle processes. Our app was not recovering correctly when relaunching from a stopped process state because we were using incorrect methods from our
DiscoveryPagerAdapter
asinput
s which did not give ourDiscoveryFragment
a proper resume kick.before:
how
DiscoveryViewModel
logic via Pass categories from DiscoveryActivity to Fragment #44.skip(1)
andtake(1)
s that we did not feel great about. Simplify overallpagerSelectedPage
logic. Feel sound with ourRxJava
knowledge and operators/Subjects/Observables.FragmentPagerAdapter
API again. This is how we found a better pager method, setPrimaryItem(). Why this is better:getItem()
only pings once each time aFragment
is created. This would not ping on return from stopped state. See FragmentPagerAdapter docs for more info.RxViewPager
'spageSelection
's immediate ping on subscribe made it difficult to sync with when the pager was actually ready.setPrimaryItem()
tells us the current page, and when the Fragment is ready. .:., better!0
delay for thepagerAdapter
inputs, since there is a frame of delay between when the Fragment is created and ready to receive the inputs. We also recently introduced the.compose(observeForUI)
vs.observeOn(AndroidSchedulers.mainThread())
pattern, and now know more about when to use which.after: