Skip to content
This repository has been archived by the owner on Apr 30, 2024. It is now read-only.

"First frame problem". #14

Closed
artem-zinnatullin opened this issue May 23, 2018 · 4 comments
Closed

"First frame problem". #14

artem-zinnatullin opened this issue May 23, 2018 · 4 comments
Assignees

Comments

@artem-zinnatullin
Copy link
Contributor

There is a common problem with async rendering: due to async data arrival and async switching to ui thread you're effectively skipping first frame.

In many cases it's not really a problem because it's very hard to notice one frame without data, especially if default layout state already displays something.

However in some cases like very different default state of the layout compared to the state with data (ie whole content is invisible by default, etc) it can be noticeable.

This GitHub issue tracks possible solutions and general discussion of this problem.

cc @alexjlockwood @kxfang

Also related to RxAndroid ReactiveX/RxAndroid#228

@artem-zinnatullin
Copy link
Contributor Author

Right now Domic renders everything by posting to Choreographer at constant time intervals.

Changes posted to Domic's DOM do skip current frame and are rendered on the next frame which is not a problem in general since data arrives asynchronously in the first place but it falls into "First frame problem" case.

Possible solution:

Expose an API to force rendering of the current buffer ie Renderer.renderCurrentBuffer() (naming is not final).

Default Renderer implementation, AndroidRenderer will render current buffer synchronously if renderCurrentBuffer() was called on main thread (throw exception if called on non main thread?).

Call to this method can be integrated into userland code or frameworks like Scoop, Fragments, Activity, etc to render current buffer when first lifecycle method finishes thus giving user a way to solve "First frame problem"

ie:

class MyActivity : Activity {

    override fun onCreate(…) {
        setContentView(R.layout.myactivity)

        // Bind Domic, push some changes to render.

        renderer.renderCurrentBuffer()
    }

}

We could do some heuristics inside Domic to make it automatic, but that doesn't look scalable and flexible enough to be able to integrate with different frameworks like Scoop.

@artem-zinnatullin
Copy link
Contributor Author

Please note that lots of apps already skip first frame due to observeOn(mainThread) applied everywhere before interaction with the view layer which posts to Handler thus skipping current frame

See also:

Solving this problem is not the goal of Domic's existence, but looks like we can do something about it in more controllable way than RxAndroid or RxBinding can since we have rendering pipeline with buffering.

@Dimezis
Copy link

Dimezis commented May 24, 2018

I'm not sure that something like renderer.renderCurrentBuffer() will work. Given your data sources are asynchronous and emitting from different threads, you might just not have all the data needed to render in Activity's onCreate.
So first of all, data sources have to have a cached data and emit it synchronously on subscription, but I suppose that kinda contradicts to Domic's idea.

@artem-zinnatullin
Copy link
Contributor Author

@Dimezis we obviously can't solve async data problem in Domic on general sense, that's not a goal and as you noted Domic is actually async-only by design

However, often times even in async systems data is cached in memory and is effectively accessed synchronously! Unless there are enforced thread jumps.

For example just yesterday @kxfang measured that about 66% of data in golden path of our app comes from memory but due to observeOn(mainThread) we're still skipping first frame.

I linked issues from other Rx projects because it's a known problem in async/reactive systems and there are cases when, yes, you're writing async code but it actually gets synchronously executed.

This API won't solve problem of async data arrival but it'll help get the first frame for data cached in memory which is not bad right :)

We won't be promoting it as "The Solution" but rather like "We did what we could on our side and gave you the tools, now it's up to you :)"

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants