0.8.0 - Jun 9, 2024
- Kotlin
2.0.0
🎉. - AndroidX Lifecycle
2.8.1
. - JetBrains Compose Multiplatform
1.6.11
. - KotlinX Coroutines
1.8.1
. - Touchlab Stately
2.0.7
. - Koin Core
3.5.6
, Koin Compose1.1.5
.
-
Added
JvmSerializable
- multiplatform reference to Javajava.io.Serializable
interface, along withNonNullSavedStateHandleKey.Companion.serializable
andNullableSavedStateHandleKey.Companion.serializable
// Use `JvmSerializable` with enum classes. enum class Gender : JvmSerializable { MALE, FEMALE, } // Create a `NonNullSavedStateHandleKey` for a serializable type. private val genderKey: NonNullSavedStateHandleKey<Gender> = NonNullSavedStateHandleKey.serializable( key = "gender", defaultValue = Gender.MALE, ) // Use `SavedStateHandle.safe` extension function to access `SavedStateHandle` in a type-safe way. val genderStateFlow: NonNullStateFlowWrapper<Gender> = savedStateHandle .safe { it.getStateFlow(genderKey) } .wrap()
-
Since Kotlin 2.0.0, you must add
"plugin:org.jetbrains.kotlin.parcelize:additionalAnnotation=com.hoc081098.kmp.viewmodel.parcelable.Parcelize"
as a free compiler argument to able to use@Parcelize
annotation in the common/shared module (Kotlin Multiplatform module).// build.gradle.kts plugins { id("kotlin-parcelize") // Apply the plugin for Android } // Since Kotlin 2.0.0, you must add the below code to your build.gradle.kts of the common/shared module (Kotlin Multiplatform module). kotlin { [...] // Other configurations targets.configureEach { val isAndroidTarget = platformType == org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.androidJvm compilations.configureEach { compileTaskProvider.configure { compilerOptions { if (isAndroidTarget) { freeCompilerArgs.addAll( "-P", "plugin:org.jetbrains.kotlin.parcelize:additionalAnnotation=com.hoc081098.kmp.viewmodel.parcelable.Parcelize", ) } } } } } }
0.7.1 - March 2, 2024
- JetBrains Compose Multiplatform
1.6.0
. - New: Add support for Kotlin/Wasm (
wasmJs
target) 🎉.
-
For more information check out the docs/0.x/viewmodel-koject-compose
-
The Koject dependency are used in
kmp-viewmodel-koject-compose
:com.moriatsushi.koject:koject-core:1.3.0
. -
New The
kmp-viewmodel-koject
artifact provides the integration ofkmp-viewmodel
,kmp-viewmodel-compose
andKoject
, helps us to retrieveViewModel
from the Koject DI container without manually dependency injection.@Provides @Singleton class MyRepository @Provides @ViewModelComponent // <-- To inject SavedStateHandle class MyViewModel( val myRepository: MyRepository, val savedStateHandle: SavedStateHandle, ) : ViewModel() { // ... } @Composable fun MyScreen( viewModel: MyViewModel = kojectKmpViewModel(), ) { // ... }
- Add Compose Multiplatform Koject sample
which shares
ViewModel
s and integrates withNavigation
in Compose Multiplatform. It usesKoject
for DI.
0.7.0 - Feb 17, 2024
- AndroidX Lifecycle
2.7.0
. - Android target: update
Compile SDK
andTarget SDK
to34
. - KotlinX Coroutines
1.8.0
.
- New: Add support for Kotlin/Wasm (
wasmJs
target) 🎉. - The behavior of
ViewModel.addCloseable(Closeable)
on non-Android targets has been changed to be consistent with Android target.ViewModel
'saddCloseable()
now immediately closes theCloseable
if theViewModel
has been cleared. This behavior is the same across all targets ✅.
-
Fixed:
koinViewModelFactory
:CreationExtras
passed toViewModelFactory.create
will now be passed to the constructor of the ViewModel if it's requested.class MyViewModel(val extras: CreationExtras) : ViewModel() val myModule: Module = module { factoryOf(::MyViewModel) } val factory = koinViewModelFactory<MyViewModel>( scope = KoinPlatformTools.defaultContext().get().scopeRegistry.rootScope, ) val extras = buildCreationExtras { /* ... */ } val viewModel: MyViewModel = factory.create(extras) viewModel.extras === extras // true <--- `viewModel.extras` is the same as `extras` passed to `factory.create(extras)`
- Add more tests to
kmp-viewmodel-compose
(android & jvm),kmp-viewmodel-koin
(common), andkmp-viewmodel-koin-compose
(common & jvm).
0.6.2 - Feb 5, 2024
-
For more information check out the docs/0.x/viewmodel-koin-compose
-
The Koin dependencies are used in
kmp-viewmodel-koin-compose
:io.insert-koin:koin-core:3.5.3
.io.insert-koin:koin-compose:1.1.2
.
-
New The
kmp-viewmodel-koin
artifact provides the integration ofkmp-viewmodel
,kmp-viewmodel-compose
andKoin
, helps us to retrieveViewModel
from the Koin DI container without manually dependency injection.class MyRepository class MyViewModel( val myRepository: MyRepository, val savedStateHandle: SavedStateHandle, val id: Int, ) : ViewModel() { // ... } val myModule: Module = module { factoryOf(::MyRepository) factoryOf(::MyViewModel) } @Composable fun MyScreen( id: Int, viewModel: MyViewModel = koinKmpViewModel( key = "MyViewModel-$id", parameters = { parametersOf(id) } ) ) { // ... }
-
For more information check out the docs/0.x/viewmodel-savedstate-safe
-
New The
kmp-viewmodel-savedstate
artifact provides the type-safe API that allows you to accessSavedStateHandle
in a type-safe way.private val searchTermKey: NonNullSavedStateHandleKey<String> = NonNullSavedStateHandleKey.string( key = "search_term", defaultValue = "" ) // Use `SavedStateHandle.safe` extension function to access `SavedStateHandle` in a type-safe way. savedStateHandle.safe { it[searchTermKey] = searchTerm } savedStateHandle.safe { it.getStateFlow(searchTermKey) } // Or use `SavedStateHandle.safe` extension property to access `SavedStateHandle` in a type-safe way. savedStateHandle.safe[searchTermKey] = searchTerm savedStateHandle.safe.getStateFlow(searchTermKey)
- New Add
rememberViewModelFactory
s to remember theViewModelFactory
s in@Composable
functions. They acceptbuilder: @DisallowComposableCalls CreationExtras.() -> VM
s.
class MyViewModel(savedStateHandle: SavedStateHandle): ViewModel()
@Composable
fun MyScreen() {
val factory: ViewModelFactory<MyViewModel> = rememberViewModelFactory {
MyViewModel(savedStateHandle = createSavedStateHandle())
}
val viewModel: MyViewModel = kmpViewModel(factory = factory)
// ...
}
-
New Add a new
kmpViewModel
overload that acceptsfactory: @DisallowComposableCalls CreationExtras.() -> VM
(Previously, it only acceptsfactory: ViewModelFactory<VM>
).class MyViewModel(savedStateHandle: SavedStateHandle): ViewModel() @Composable fun MyScreen( viewModel: MyViewModel = kmpViewModel { MyViewModel(savedStateHandle = createSavedStateHandle()) } ) { // ... }
The above
kmpViewModel
usesrememberViewModelFactory
internally. UserememberViewModelFactory { ... }
andkmpViewModel(factory = factory)
is the same as usingkmpViewModel { ... }
.
0.6.1 - Dec 10, 2023
- On non-Android targets:
ViewModel.viewModelScope
does not useDispatchers.Default
as a fallback. That means theCoroutineDispatcher
ofViewModel.viewModelScope
isDispatchers.Main.immediate
orDispatchers.Main
.
- Refactor example code.
- Add NOTE about the
kotlinx-coroutines
dependency when targetingDesktop
(aka.jvm
).
0.6.0 - Dec 8, 2023
- Remove now-unsupported targets:
iosArm32
,watchosX86
.
-
MutableCreationExtras
has been renamed toMutableCreationExtrasBuilder
, and it does not inherit fromCreationExtras
anymore. Because of this, a new methodMutableCreationExtrasBuilder.asCreationExtras()
has been introduced can be used to convert a builder back toCreationExtras
as needed.NOTE:
buildCreationExtras
andCreationExtras.edit
methods are still the same as before.// Old version (0.5.0) val creationExtras: CreationExtras = MutableCreationExtras().apply { // ... } // New version (0.6.0): `MutableCreationExtras` does not inherit from `CreationExtras` anymore. val creationExtras: CreationExtras = MutableCreationExtrasBuilder().apply { // ... }.asCreationExtras() // <--- asCreationExtras: convert a builder back to `CreationExtras` as needed.
More details: with Kotlin 1.9.20, an expect with default arguments are no longer permitted when an actual is a typealias (see KT-57614), we cannot use
actual typealias MutableCreationExtras = androidx.lifecycle.viewmodel.MutableCreationExtras
. So we have to use wrapper class instead. -
Update the docs of
ViewModel.viewModelScope
to clarify that the scope is thread-safe on both Android and non-Android targets. -
On non-Android targets
ViewModel.clear()
method has been refactored to improve the performance.- Any
Exception
thrown fromCloseable.close()
will be re-thrown asRuntimeException
.
0.5.0 - Sep 27, 2023
- Kotlin
1.9.0
. - AndroidX Lifecycle
2.6.1
. - KotlinX Coroutines
1.7.3
. - Android Gradle Plugin
8.1.0
.
- Add
ViewModelStore
andViewModelStoreOwner
. - Add
ViewModelFactory
andVIEW_MODEL_KEY
. - Add
CreationExtras
andCreationExtrasKey
. - Add
buildCreationExtras
andCreationExtras.edit
. - Add
ViewModel.isCleared()
method to check if theViewModel
is cleared, only available on non-Android targets. - Add
MainThread
(moved fromviewmodel-savedstate
module).
- Remove
MainThread
(moved toviewmodel
module). - Add
SavedStateHandleFactory
interface. - Add
SAVED_STATE_HANDLE_FACTORY_KEY
andCreationExtras.createSavedStateHandle()
.
-
A new module allows to access
ViewModel
s in Jetpack Compose Multiplatform.kmpViewModel
to retrieveViewModel
s in @Composable functions.LocalSavedStateHandleFactory
andSavedStateHandleFactoryProvider
to get/provideSavedStateHandleFactory
in @Composable functions. It allows integration with any navigation library.LocalViewModelStoreOwner
andViewModelStoreOwnerProvider
to get/provideViewModelStoreOwner
in @Composable functions. It allows integration with any navigation library.defaultPlatformCreationExtras
anddefaultPlatformViewModelStoreOwner
to get the defaultCreationExtras
andViewModelStoreOwner
, which depends on the platform.
-
Dependencies: Compose Multiplatform 1.5.0.
-
Docs: 0.x Viewmodel-Compose docs.
-
Refactor example code.
-
Add Compose Multiplatform Koin sample which shares
ViewModel
s and integrates withNavigation
in Compose Multiplatform. -
Add Compose Multiplatform KmpViewModel KMM Unsplash Sample, a KMP template of the Unsplash App using Compose multiplatform for Android, Desktop, iOS. Share everything including data, domain, presentation, and UI.
-
Add more docs: 0.x docs.
-
Add more tests.
0.4.0 - Apr 7, 2023
- Kotlin
1.8.10
. - Target
Java 11
. - Touchlab Stately
1.2.5
. - AndroidX Lifecycle
2.6.0
. - Android Gradle Plugin
7.4.2
.
-
Add
NonNullStateFlowWrapper
andNullableFlowWrapper
to common source set. -
Move all
Flow
wrappers to common source set. Previously, they were only available forDarwin targets
(iOS
,macOS
,tvOS
,watchOS
). -
Add
Flow.wrap()
extension methods to wrapFlow
s sources:Flow<T: Any>.wrap(): NonNullFlowWrapper<T>
.Flow<T>.wrap(): NullableFlowWrapper<T>
.StateFlow<T: Any>.wrap(): NonNullStateFlowWrapper<T>
.StateFlow<T>.wrap(): NullableStateFlowWrapper<T>
.
In common code, you can use these methods to wrap
Flow
sources and use them in Swift code easily.// Kotlin code data class State(...) class SharedViewModel : ViewModel() { private val _state = MutableStateFlow(State(...)) val stateFlow: NonNullStateFlowWrapper<State> = _state.wrap() }
// Swift code @MainActor class IosViewModel: ObservableObject { private let vm: SharedViewModel @Published private(set) var state: State init(viewModel: SharedViewModel) { vm = viewModel state = vm.stateFlow.value // <--- Use `value` property with type safety (do not need to cast). vm.stateFlow.subscribe( // <--- Use `subscribe(scope:onValue:)` method directly. scope: vm.viewModelScope, onValue: { [weak self] in self?.state = $0 } ) } deinit { vm.clear() } }
- Refactor example code.
- Add more docs: 0.x docs.
- Add more tests.
0.3.0 - Mar 18, 2023
- Add
NonNullFlowWrapper
andNullableFlowWrapper
, that are wrappers forFlow
s that provides a more convenient API for subscribing to theFlow
s onDarwin targets
(iOS
,macOS
,tvOS
,watchOS
)// Kotlin code val flow: StateFlow<Int>
// Swift code NonNullFlowWrapper<KotlinInt>(flow: flow).subscribe( scope: scope, onValue: { print("Received ", $0) } )
- Add more example, refactor example code.
- Add more docs: 0.x docs.
- Add more tests.
- Gradle
8.0.2
. - Dokka
1.8.10
.
0.2.0 - Mar 5, 2023
-
Add
kmp-viewmodel-savedstate
artifact. This artifact brings:- Android Parcelable interface.
- The
@Parcelize
annotation from kotlin-parcelize compiler plugin. - SavedStateHandle class.
to Kotlin Multiplatform, so they can be used in common code. This is typically used for state/data preservation over Android configuration changes and system-initiated process death , when writing common code targeting Android.
- Add more example, refactor example code.
- Add more docs: 0.x docs.
0.1.0 - Feb 18, 2023
- Make
ViewModel.viewModelScope
public.
- Add an
ViewModel.addCloseable
API and a new constructor overloadconstructor(vararg closeables: Closeable)
, that allow you to add one or moreCloseable
objects to theViewModel
that will be closed when theViewModel
is cleared without requiring any manual work inonCleared()
.
0.0.1 - Feb 11, 2023
- Initial release.