https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
d

Daniele B

09/17/2020, 5:54 PM
Another great milestone today, after
Android
and
iOS
, I was able to run the shared ViewModel on
Web
too! I admit I never used
React
before, but with Kotlin it was incredibly easy to setup it up! I was actually thinking to use
Vue.js
for the web, because I was interested in a lightweight web framework, whose main capability is to provide a declarative UI, similar to what Compose and SwiftUI provide in mobile. But I was not aware of how simple Kotlin makes it to work with React! I am still astonished now. Kotlin hides most React complexity, and Android Studio even spins a node.js server on localhost to test the app, with no setup! My project uses a shared ViewModel, which means that changes to the app state only happen in the shared code. Such changes are then propagated via
StateFlow
to the platform-specific app code. In Kotlin/React it’s as simple as this to observe the app state changes via StateFlow:
Copy code
fun myAppState() : AppState {
    val appDependencies = useContext(AppDependenciesContext)
    val (state, setState) = useState(appDependencies.coreModel.stateFlow.value)

    useEffectWithCleanup {
        val job = appDependencies.coreModel.stateFlow.onEach { setState(it) }.launchIn(GlobalScope)
        return@useEffectWithCleanup { job.cancel() }
    }
    
    return state
}
💯 5
K 2
👍 2
b

Big Chungus

09/17/2020, 7:14 PM
Any chance you could share the project? Would be interesting to have a look at your setup.
d

Daniele B

09/17/2020, 7:17 PM
I am working at a private project, but I might publish a minimal project on a repository soon
b

Big Chungus

09/17/2020, 7:18 PM
Would be great to see even a stripped down version of it with just 2 views or so
d

Daniele B

09/17/2020, 7:18 PM
The React part I have just done it today. I am still learning about Kotlin/React
b

Big Chungus

09/17/2020, 7:26 PM
No, I'm familiar with all that. I'm interested in how it all comes together
Essentially your setup
a

ankushg

09/17/2020, 7:41 PM
I’m particularly interested in how you’re modeling your ViewModel and Navigation 😊 Even a stripped down example without real logic would be a great help
d

Daniele B

09/17/2020, 8:04 PM
This is an high level architecture.
I think I am going to write an article soon, where I explain things more in details.
💯 1
👍 3
a

ankushg

09/17/2020, 9:35 PM
Nice! I saw your high level architecture before, and it’s definitely in line with what I’ve got for Android I’m currently struggling with conceptualizing how to scale it out to model multi-screen flows across platforms... Do you have one big ViewModel and every different screen is just an instance of a
sealed class ViewState
? Or do you use a different ViewModel for each screen and maybe one big ViewModel to represent the global nav state?
⬆️ 1
d

Daniele B

09/17/2020, 9:41 PM
At the moment I am using just one ViewModel for the whole app. The ViewModel exposes all intents/events. The ViewModel also instantiates the StateFlow, which is the communication channel to pass the state to the platform-specific apps.
k

Kurt Renzo Acosta

09/17/2020, 9:47 PM
I’m curious. I always managed navigation at the view layer. Is it a practice to manage it in the ViewModels? Could you give a code snippet on how you do it?
d

Daniele B

09/17/2020, 9:49 PM
The navigation state is just like any other state. It can easily be part of the AppState, managed on the shared ViewModel.
Even texts/localization can be managed in the shared ViewModel.
k

Kurt Renzo Acosta

09/17/2020, 9:52 PM
Yes I know. But I never managed navigation as states but rather as events like on a flow
navigateToScreen2
then the view layer is just observing it and doing a
navController.navigate(R.id.action)
or on iOS, do a navigate via coordinator. Is this the same thing you’re referring to?
d

Daniele B

09/17/2020, 9:55 PM
I am not sure I am following. Consider that I am using declarative UIs in all platforms (Compose for Android, SwiftUI for iOS, React for Web). When you write
navController.navigate(R.id.action)
it feels like you are using the traditional Android View system.
The architecture I am describing is not applicable to the traditional Android View system or the iOS Storyboard system.
k

Kurt Renzo Acosta

09/17/2020, 10:02 PM
I guess. Time to get my hands dirty with compose then.
d

Daniele B

09/17/2020, 10:03 PM
Yes, I believe Kotlin MultiPlatform makes sense if you jump into the declarative UIs, otherwise it’s just a waste of time. The sooner you switch to declarative UIs, the sooner you realize the amazing productivity of KMP, which simplifies app development by an order of magnitude.
k

Kurt Renzo Acosta

09/17/2020, 10:04 PM
That I have to contest. We have a working system using current view systems. Business logic should be pluggable to any UI system. If it’s not, then you’re business logic might be tightly coupled to a framework
d

Daniele B

09/17/2020, 10:06 PM
In case you have to deal with an old app, of course you can still use KMP, but for a smaller portion of the app.
With declarative UIs, you are able to use KMP for at least 85% of the app code.
k

Kurt Renzo Acosta

09/17/2020, 10:09 PM
Not really. I’m sharing everything from ViewModel up to networking and caching and it works fine! Much like your level of 85%. Haven’t updated it to 1.4 due to a blocker but it’s in the works.
d

Daniele B

09/17/2020, 10:13 PM
If you run the same app using JetpackCompose, you will see how smaller the UI code is.
k

Kurt Renzo Acosta

09/17/2020, 10:17 PM
Yup I definitely get that but what I'm saying is KMP should work independently from a view system. I'm looking at the sample now and now I see how you could manage the navigation state easily rather than the traditional one using events. Can't wait for this to go into production. Hope you could make a Github repository for your project. It would definitely be interesting to take a look at it!
d

Daniele B

09/17/2020, 10:21 PM
Yes, KMP can be used at any level. This makes it suitable also for old apps that cannot be fully rewritten. But when we think about the future of mobile, we associate KMP to the declarative UIs and to the MVI pattern. Because in such case, we can really build a very simple and robust architecture, with no boilerplate code.
d

darkmoon_uk

09/18/2020, 8:02 AM
Kicking goals @Daniele B 👍
d

Daniele B

09/20/2020, 2:31 PM
I publish here an improved version of the code for observing the StateFlow on Kotlin/React:
Copy code
external interface ViewModelProps : RProps {
    var viewModel : CoreViewModel
}

val App = functionalComponent<ViewModelProps> { props ->
    val model = props.viewModel
    val (state, setState) = useState(model.stateFlow.value)

    useEffectWithCleanup {
        val job = model.stateFlow.onEach {
            if (it != state) {
                setState(it)
            }
        }.launchIn(GlobalScope)
        return@useEffectWithCleanup { job.cancel() }
    }

}
It’s important to check if the state value is different before calling setState(). Otherwise each rendering always happens twice.
2 Views