~4 years • Selling train tickets for ~2.5 years • Passionate about building scalable app architectures • Outside of work I like space exploration, chess, Man City, and UFC A bit about me
• What is Molecule? • A brief intro to writing Molecule code • How Molecule fits into our traditional Android presentation architectures • What real-world problems does it solve? • Simplifying the logic expansion of the ViewModel • Combining flows with compose-style declarative code • Building reusable state management for reusable UI components
you already use) “It [Molecule] allows you to use the compiler magic of Compose for the pure manipulation of data… just aggregating inputs and emitting outputs.”
@Composable fun Profile() { val user by userFlow.collectAsState(null) val balance by balanceFlow.collectAsState(0L) if (user == null) { Text("Loading…") } else { Text("${user.name} - $balance") } }
val user by userFlow.collectAsState(null) val balance by balanceFlow.collectAsState(0L) return if (user == null) { ProfileModel.Loading } else { ProfileModel.Data(user.name, balance) } } val userFlow = db.userObservable() val balanceFlow = db.balanceObservable() val models: StateFlow<ProfileModel> = scope.launchMolecule(mode = ContextClock) { profilePresenter(userFlow, balanceFlow) } Another example
favourite kind • In simple terms, the key di ff erences from MVVM are: • Strictly one single state representing the whole screen • One stream of inputs (referred to as intents) represented in some structured way (e.g a sealed class) • (Optional) Some “reducer” mechanism that separates state changes from the rest of the ViewModel logic in an easily testable way.
other fl ow testing methodology) @Test fun `GIVEN randomise event is received THEN new player data is loaded`() = runTest { val input = flowOf(RandomiseClicked, RandomiseClicked) ... moleculeFlow(RecompositionMode.Immediate) { sut.present(events = input) }.test { assertEquals(PlayerComponentState.Loading, awaitItem()) assertEquals(fakePlayer1InfoState, awaitItem()) assertEquals(PlayerComponentState.Loading, awaitItem()) assertEquals(fakePlayer2InfoState, awaitItem()) assertEquals(PlayerComponentState.Loading, awaitItem()) assertEquals(fakePlayer3InfoState, awaitItem()) } }
for non-ui purposes • It allows us to write compose for our presentation logic • It’s fun! • Using the Molecule ViewModel we can create VMs that scale much better than more traditional methods • It lets us combine multiple streams of data in a readable and imperative style • It’s really great for decoupling the logic for a reusable ui component from the ViewModel of each screen