Page tree
Skip to end of metadata
Go to start of metadata

As described in Design patterns in UI content appViewContext 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:

 * Marker interface of a view context.
public interface ViewContext {
However, by design it is associated with a ContextProperty:
public interface ContextProperty<T> extends Serializable {

    Disposable observeNullable(Consumer<T> action);

    Disposable observe(Consumer<Optional<T>> action);

    Optional<T> value();

    void set(T value);

    void mutate(Consumer<T> mutator);

Typical usage pattern of the ViewContext is e.g. LocationContext:
public interface LocationContext extends ViewContext {

    ContextProperty<BrowserLocation> location();
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 ViewContextProxy which can generate the implementation of any interface extending ViewContext by pre-creating an instance of a default impl of ContextProperty per 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 extensionsUiFrameworkView is supplied with bindContext API which will at the same time create and instance of the context and will share it in the view's BeanStore so 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). ViewContext is 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 Destructible interface is proposed.

  • No labels