Kotlin Multiplatform Tales: A Shared ViewModel
Note: Our posts will generally be about Kotlin Multiplatform for iOS & Android (KMM)
At Double Symmetry, we’ve been using Kotlin Multiplatform (KMP) for building iOS and Android applications for the last two years. KMP’s ability to share Kotlin code between different platforms has enabled our team to continue building beautiful native UI while sharing our platform independent code. For the last two years, our goal with KMP has been to maximise the amount of code that can be shared between platforms while also aiming to not lose the commodities of each.
The Problem Space
At the moment most apps (we know of) use KMP to share their data/domain layer between platforms.. in this post we’ll take this one step further — bringing sharing to the presentation layer! At Double Symmetry, the presentation layer of the apps we build is built on the MVVM(-C) pattern. Therefore a very important part of our apps and shared code is the ViewModel.
Requirements for a Shared ViewModel
On Android, Jetpack provides a ViewModel
class which is automatically tied to scope (usually a fragment, an activity or a composable) and is retained for as long as that scope is alive. It also makes available a CoroutineScope
that's tied to this ViewModel
's lifecycle which can be used for writing your business logic.
If we’re to create a shared view model we’d like the following:
- On Android our
ViewModel
should also be able to leverage lifecycle awareness. - Our ViewModel should provide a
CoroutineScope
that we can use.
Implementation
We’ll start by defining our base ViewModel
class that exposes a CoroutineScope
as we'd expect from our requirements:
Simple enough! Now let’s work on our Android definition. The requirement is that we can also leverage lifecycle awareness.. so should we figure out how Jetpack’s ViewModel
does it? No need. Let's use that!
Voila! Now on Android our instances of BaseViewModel
will conform to all the sweet commodities we'd expect and exposes a CoroutineScope
. But what about iOS?
Not as straightforward. But also not complicated. When a scope
is requested, we first check if one has already been created and return it, or we create a new one. We also don't have an automatic way to bind to the lifecycle of a UIViewController
so we'll have to expose a method that should be called on deinit
to clear the scope.
Using the ViewModel
Now that we’ve got a ViewModel
we can write our business logic for both platforms!
Beautiful ✨
Thanks for reading this article! I hope this library makes sharing business logic easier for you and your team while building your application.
Are you building mobile apps and overpaying for Github Actions in your private repos? Check out Blaze — Apple Silicon runners designed to reduce your build time at a much lower cost.
If you’re looking for the full implementation of the ViewModel
, we've published the above as a small library on Github that you can use in your projects.