As described in Design patterns in UI content app,
ViewContext is a unit of a state and its aim is to setup flexible communication between the views and store the context information.
The interface itself is just a marker:However, by design it is associated with a
ContextProperty: Typical usage pattern of the
LocationContext: Default implementation of a ContextProperty is very predictable (currently based on rxJava observable which can be easily phased out if needed). In order to reduce the amount of boilerplate code required to start using a context we have created a dynamic proxy utility called
ViewContextProxywhich can generate the implementation of any interface extending
ViewContextby pre-creating an instance of a default impl of
ContextPropertyper every method which returns it. However one does not need to use such proxy directly every time they need to create context: as described in View interface extensions,
UiFrameworkViewis supplied with
bindContextAPI which will at the same time create and instance of the context and will share it in the view's
BeanStoreso that the child views can inject it.
Similarities to EventBus
ViewContext concept to some extent resembles the event bus: both can be shared between the UI parts, both can communicate the events/changes. The main advantages of the
ViewContext compared to the event bus are:
- while there can only be one EventBus in the UI scope, there can be as many view contexts as needed, which can improve code readability (the component directly injects the context interfaces instead of injecting the eventbus and then subscribing to the events somewhere in its own guts.
- EventBus is stateless, while view context is persistent, in this case statefulness is good, because the subscribers of the context are relieved from having to cache the state themselves. Besides it is quite convenient that once a new subscriber attaches to the context, they may effortlessly get the latest value and hence to be in synch with surrounding UI state.
- EventBus pattern encourages to write at least an event class (container for data) and a handler interface and then implement such interface at every subscription place (okay, lambdas help a bit, but that is not the point).
ViewContextis pretty boilerplate-free.
Preventing contexts from leaking
Similarly to the event buses, there's a danger of view context causing a memory leak (even though possibly not such as bad as event bus):
- a child view attaches to the context
- then it is removed/destroyed with out explicitly releasing the subscription
- the subscription will hang forever and may prevent the related object from being garbage collected
- → memory leak
In order to overcome that we can use a similar technique to the one we use for the event buses: whenever a child view tries to inject a view context from the parent view - wrap the view context into a protecting decorator:
- take all the properties of the parent context and wrap them with a new one that will delegate all the subscriptions to the wrapee, but will store them separately
- when the child view is destroyed - automatically remove all the subscriptions in the wrapper. For that the
Destructibleinterface is proposed.