Tuesday, August 4, 2020

Enforcing expected ordering in coroutines

A recent update to PYDroid brings it to 22.0.2 and brings with it two small but major changes.

First is the bump from the bundled Material dependency in pydroid-ui, moving from 1.1.0 to 1.2.0, hooray! See the changelog for the material-components library for details.

Second is a change to how the UiViewModel binds the view and controller. Before, the UiViewModel would launch multiple coroutines on the IO dispatcher and request to bind the controller event bus, the views event busses - then initialize the views - and then bind the state event bus and run the first render. Because these launches were all happening inside the same coroutine scope, they were queued in order but ran sometimes in parallel or even out of order - which goes against the expectation of a strict initialization ordering that the library guaranteed. Because of this lack of order, there were sometimes cases where the UiViewModel initialization could run before the controller event bus was bound, so any publish calls from inside the UiViewModel during initialization would get lost. Similar edge cases were possible in communications from the Views to the ViewModel.

The new version should address these edge cases, by making sure that the bus binding operations happen in order by launching the coroutine on the Main dispatcher, which is a single threaded unbound queue backed by the Main thread, and then immediately switching to an IO context to do their actual work. By queueing the work this way, this should guarantee the following flow

Controller bus is bound
View busses are bound
ViewModel is initialized, calls to publish() from a doOnInit block should reliably reach the Controller
Views are initialized in FIFO order, calls to publish() from a doOnInflate block should reliably reach the ViewModel
State bus is bound, any future calls to setState will emit a change to the view layer, but any setState calls before this will simply update the currently held state object without emitting any UI changes
The initial or most recent state of the UI is rendered.

Note that this flow has not changed, it was always intended to be this way - but hopefully with these changes this flow is even more strictly enforced.

As a side benefit to using the Main dispatcher as a queue, we can remove the unique stateContextDispatcher which was backed by a newSingleThreadedExecutor for each ViewModel, reducing the number of extra threads we are creating and destroying - since threads are expensive on Android this can be a nice benefit.

FridgeFriend finally got an icon today and the store page is beginning preparation for a release. Wow. It's been a while hasn't it.

Stay tuned!

========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================