-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Android UI dispatcher and isDispatchNeeded #381
Comments
Please elaborate why do you need it. |
I want to consume values of a launch(UI) {
receiveChannel.consumeEach { value ->
// stuff
}
} In the other side, I'm not sure 100% if |
Instead of extending
Does it solve your problem? |
I also think of some solutions can solve my problem. With my opinion, my problem is quite general so I open this issue whether we can official support within the library. |
Related to #258 |
We can't implement it as is, because accidental usage of such dispatcher will lead to spurious We should provide something more explicit, e.g. new coroutine start mode or additional extension like Feel free to provide your option, the only requirement is that in place invocation should be explicit |
I agree dispatching is somehow difficult to apprehend, and explicit dispatching option is mandatory. I ended up doing a dedicated function to easily manage dispatching in UI: fun uiJob(dispatch: Boolean = uiDispatch, block: suspend CoroutineScope.() -> Unit) : Job {
return launch(UI, if (dispatch) CoroutineStart.DEFAULT else CoroutineStart.UNDISPATCHED, block = block)
} With Would rather be a kotlinx-coroutines(-android) helper |
Thanks for the feedback! I'll try to prototype |
That would be great, I could get rid of my workaround :) |
@qwwdfsad I like the About the technique to check the UI thread, I dislike using |
This might be orthogonal to some of the issues you're trying to address here but... If the primary issue is latency between posted The constructor it uses has been there in AOSP nearly since the vsync barriers debuted in Jellybean so a hacky backport is possible in a support/androidx lib, we just haven't added it there yet. You can do your own for testing with something like this:
Then you can construct a HandlerContext with an async handler for the main thread that doesn't get blocked by UI operations: Some folks working with RxAndroid saw some significant performance/latency benefits from this in testing and there's a PR over there in progress to use the same underlying mechanism: ReactiveX/RxAndroid#416 |
…ks which are invoked from the right context Fixes #381
@LouisCAD I don't mind additionally optimizing it, but it's good to know it's worth it. @adamp Thanks! Let's see how this PR is going. One already can create coroutines dispatcher over any |
It might be better in the long term to make the The whole vsync barrier thing was a requirement for us to keep behavioral compatibility with a lot of existing code at the time but it's almost never what you want in new code and the latency hit is pretty huge. The pattern it was made to protect is this:
Where the I can't think of a good reason why someone would write a suspending version of something like |
Created #427 for discussing it |
@qwwdfsad I had written tests for this before taking my decision: https://github.com/LouisCAD/Splitties/blob/beb45da8ede57383aec489ac9d5630e79db60cc9/checkedlazy/src/androidTest/java/splitties/checkedlazy/PerformanceTest.kt |
Regarding the original problem - getting dispatch behavior similar to It also looks like skipping dispatch in the manner proposed here also breaks some ordering guarantees. Consider:
If message B and C were the result of dequeuing some sort of work from the same queue, they're now out of order. This might happen many layers deep in the associated code and be very difficult to track. A number of RxJava users in the Android community have written Schedulers that behave this way and got bit by ordering bugs like the above. The answer on that side of things has usually been either, "don't use observeOn if you need it to run synchronously" ( |
If you want Message B to run after Message A and before Message C, with
coroutines, you just have to launch a single coroutine, which executes
sequentially (i.e. in order), instead of launching multiple coroutines. The
syntax of coroutines make it hard to have a bug like you describe
unintentionally, regardless of whether there's dispatch or not.
…On Mon, Jul 9, 2018, 8:19 PM Adam Powell ***@***.***> wrote:
Regarding the original problem - getting dispatch behavior similar to
LiveData where downstream behavior can interrupt or otherwise affect the
rest of the dispatch - it sounds like you either want observers that need
to affect the dispatch to use Unconfined or the wrapped dispatcher
proposed above. However, using anything other than Unconfined here means
that under some circumstances that might not be easily reproduced, your
observer won't be able to affect the upstream dispatch, but it might assume
it can. That sounds like a recipe for bugs.
It also looks like skipping dispatch in the manner proposed here also
breaks some ordering guarantees. Consider:
1. Message A is posted to the Handler
2. Message B is posted to the Handler
3. Message A executes, performs some operation that results in
processing and dispatch of Message C
4. Message C skips dispatch and executes immediately since it's on the
main thread already
5. Message B executes after Message C has executed
If message B and C were the result of dequeuing some sort of work from the
same queue, they're now out of order. This might happen many layers deep in
the associated code and be very difficult to track.
A number of RxJava users in the Android community have written Schedulers
that behave this way and got bit by ordering bugs like the above. The
answer on that side of things has usually been either, "don't use observeOn
if you need it to run synchronously" (Unconfined) or to address the
latency issues that come from the vsync barriers if that's the motivation.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#381 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AGpvBaio7HbCr0QY2qoQa_WfEVpffwgaks5uE56UgaJpZM4UYMo5>
.
|
Nothing about coroutines precludes the ability to have the above problem. The use a single coroutine represents only a fraction of the interaction with a single-threaded scheduler. |
It's harder, for sure. It could still interact poorly with other code a couple layers away though, and giving it prominent placement in the API could lead people to think that it's a general purpose, "go faster" button when it may not be addressing the right problems. It seems like the example code at the beginning of the thread assumes that the channel consumer will fully finish processing the item before the producer continues dispatching rather than just receive the item from the channel, this being the |
…ks which are invoked from the right context Fixes #381
…ks which are invoked from the right context Fixes #381
…ks which are invoked from the right context Fixes #381
Could we change implementation of method
HandlerContext.isDispatchNeeded()
to be more flexible:The text was updated successfully, but these errors were encountered: