LeOS-Ice-browser/android-components/docs/_posts/2019-09-02-browser-state.md

5.0 KiB

layout title date author
post browser-state: Better state management for apps and components 2019-09-02 10:30:00 +0200 sebastian

We have been working on a new component called browser-state to eventually replace browser-session. Now we are ready to start migrating components from browser-session to browser-state. This blog posting explains why we want to decommission browser-session, describes how browser-state works and what our migration plans are.

What's the problem with browser-session?

For maintaining the global browser state (e.g. "What tabs are open? What URLs are they pointing to?") the Android Components project provides the browser-session component. The initial implementation of browser-session was a clean, generic re-implementation of what we had developed (more organically) for Firefox Focus.

In 2018 we noticed some flaws in the design of browser-session. Those flaws came down to being able to observe the state while being able to modify it at the same time ("mutable state"). This unintended behavior could lead to "event order issues" and observers not really seeing a particular state change. Luckily back then we hadn't seen those issues causing any problems in our apps yet.

We looked at multiple ways to prevent those side effects but that turned out to be almost impossible as long as the state is mutable. After more brainstorming, researching and prototyping we came up with a new design for a completely new component called browser-state to eventually replace browser-session.

In 2019 we completed and tweaked the design of the new browser-state component until we felt that it was ready to be used in other components.

A closer look at browser-state

Concepts used in the browser-state component are similar to Redux - a state container library for JavaScript. The Redux documentation is a great way to get familiar with some of the concepts:

BrowserState

The global state of the browser is represented by an instance of an immutable data class: BrowserState (API). Since it is immutable, an instance of this data class can be observed and processed without any side effects changing it. A state change is represented by the creation of a new BrowserState instance.

BrowserStore

The BrowserStore (API) is the single source of truth. It holds the current BrowserState instance and components, as well as app code, can observe it in order to always receive the latest BrowserState. The only way to change the state is by dispatching a BrowserAction (API) on the store. A dispatched BrowserAction will be processed internally and a new BrowserState object will be emitted by the store.

How are we going to migrate apps and components to browser-state?

The browser-session component is at the heart of many components and most apps using our components. It is obvious that we cannot migrate all components and apps from browser-session to browser-state from one Android Components release to the next one. Therefore the Android Components team made it possible to use browser-state and browser-session simultaneously and keep the state in both components synchronized.

val store = BrowserStore()

// Passing the BrowserStore instance to SessionManager makes sure that both
// components will be kept in sync.
val sessionManager = SessionManager(engine, store)

With the ability to use both components simultaneously, the Android Components team will start migrating components over from browser-session to browser-state. As part of this work the Android Components team will extend and add to BrowserState to eventually reach feature parity with the state in SessionManager and Session. The only thing that may be different for app teams is that some components may require a BrowserStore instance instead of a SessionManager instance after migration.

// Before the migration
feature = ToolbarFeature(
    layout.toolbar,
    components.sessionManager,
    components.sessionUseCases.loadUrl,
    components.defaultSearchUseCase)

// After the migration
feature = ToolbarFeature(
    layout.toolbar,
    components.store,
    components.sessionUseCases.loadUrl,
    components.defaultSearchUseCase)

Once the migration of components is largely done, the Android Components team will start to help the app teams to plan migrating app code from browser-session to browser-state.