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-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
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
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
Concepts used in the
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
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-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-state from one Android Components release to the next one. Therefore the Android Components team made it possible to use
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-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
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