8000 Refactor Discovery to properly recover from stopped processes by luoser · Pull Request #48 · kickstarter/android-oss · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

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

Merged
merged 18 commits into from
Jan 18, 2017

Conversation

luoser
Copy link
Contributor
@luoser luoser commented Jan 17, 2017

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 as inputs which did not give our DiscoveryFragment a proper resume kick.

before:

process-no-bueno

how

  1. Disentangle DiscoveryViewModel logic via Pass categories from DiscoveryActivity to Fragment #44.
  2. Reliably reproduce the bug using Android's DDMS. This was the main challenge. This SO answer was very helpful.
  3. Debug the skip(1) and take(1)s that we did not feel great about. Simplify overall pagerSelectedPage logic. Feel sound with our RxJava knowledge and operators/Subjects/Observables.
  4. Investigate FragmentPagerAdapter API again. This is how we found a better pager method, setPrimaryItem(). Why this is better:
    • getItem() only pings once each time a Fragment is created. This would not ping on return from stopped state. See FragmentPagerAdapter docs for more info.
    • RxViewPager's pageSelection'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!
  5. Investigate our concern with observing on the main thread within the VM. Turns out we do want a 0 delay for the pagerAdapter 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:

process-bueno

luoser and others added 16 commits January 5, 2017 10:42
Pass along the root categories from the activity instead, via the pagerAdapter.
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.
@willisplummer
Copy link

👏

Copy link
Contributor
@christopherwright christopherwright left a 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
Copy link
Contributor

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 RecyclerViews; 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 use observeForUI to execute the work immediately rather than wait for a frame.

PR 230 in the old repo goes into more detail.

@luoser luoser merged commit 87bd62d into master Jan 18, 2017
@luoser luoser deleted the disco-process branch January 18, 2017 23:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0