
Lightweight library to retain object instances across lifecycle scopes with simple retain delegates, direct access to saved-state and coroutine scope, navigation/compose integration, and auto-close cleanup.
Retained is a lightweight Kotlin Multiplatform library built on top of AndroidX ViewModel. It provides a unified API to retain object instances across Kotlin Multiplatform targets.
ViewModel inheritance.ViewModelProvider.Factory.ViewModel properties: CoroutineScope (viewModelScope), SavedStateHandle, and parameters.AutoCloseable.dependencies {
// Core Kotlin Multiplatform support
implementation 'dev.marcellogalhardo:retained-core:{Tag}'
// `Activity` support
implementation 'dev.marcellogalhardo:retained-activity:{Tag}'
// `Fragment` support (includes `Activity` support)
implementation 'dev.marcellogalhardo:retained-fragment:{Tag}'
// Navigation support
implementation 'dev.marcellogalhardo:retained-navigation:{Tag}'
// Navigation with Fragment support (includes `Navigation` support)
implementation 'dev.marcellogalhardo:retained-navigation-fragment:{Tag}'
// Compose support (Android, iOS, Desktop)
implementation 'dev.marcellogalhardo:retained-compose:{Tag}'
// View support (experimental)
implementation 'dev.marcellogalhardo:retained-view:{Tag}'
implementation 'dev.marcellogalhardo:retained-navigation-view:{Tag}'
}(Replace {Tag} with the latest release version)
This section shows how to retain instances in activities and fragments. All examples use this class:
class Presenter(var counter: Int = 0)// Retain an instance in an Activity:
class CounterActivity : AppCompatActivity() {
private val presenter: Presenter by retain { Presenter() }
}
// Retain an instance in a Fragment:
class CounterFragment : Fragment() {
private val presenter: Presenter by retain { Presenter() }
}
// Share an instance between Fragments scoped to the Activity
class CounterFragment : Fragment() {
private val sharedPresenter: Presenter by retainInActivity { Presenter() }
}
// Share an instance between Fragments scoped to the NavGraph
class CounterFragment : Fragment() {
private val presenter: Presenter by retainInNavGraph(R.navigation.nav_graph) { Presenter() }
}@Composable
fun CounterScreen() {
// Scope to LocalViewModelStoreOwner (default)
val presenter = retain { Presenter() }
// Scope to ComponentActivity (Android)
val activityPresenter = retainInActivity { Presenter() }
// Scope to a specific ViewModelStoreOwner (e.g. NavBackStackEntry)
val navBackStackEntry: NavBackStackEntry // Find NavBackStackEntry
val scopedPresenter = retain(owner = navBackStackEntry) { Presenter() }
}When you retain an instance, RetainedEntry provides access to host parameters.
@Composable
fun CounterScreen() {
val presenter = retain { entry: RetainedEntry ->
Presenter()
}
// ...
}RetainedEntry provides a SavedStateHandle to save and restore state.
class CounterFragment : Fragment() {
private val presenter: Presenter by retain { entry ->
Presenter(counter = entry.savedStateHandle.get<Int>("count") ?: 0)
}
// ...
}RetainedEntry provides a CoroutineScope that matches viewModelScope.
class Presenter(scope: CoroutineScope) { /* ... */ }
class SampleFragment : Fragment() {
private val presenter: Presenter by retain { entry ->
Presenter(scope = entry.coroutineScope)
}
// ...
}For more details, see RetainedEntry.
If a retained instance implements AutoCloseable, retained automatically closes it when the host ViewModel is cleared (ViewModel.onCleared).
class ResourcePresenter : AutoCloseable {
override fun close() {
// Automatically called when the host ViewModel is cleared
}
}You can also retain instances in a View. Use these modules:
dependencies {
implementation 'dev.marcellogalhardo:retained-view:{Tag}'
implementation 'dev.marcellogalhardo:retained-navigation-view:{Tag}'
}The retained-view module provides retain and retainInActivity to scope instances to an Activity or Fragment. The retained-navigation-view module provides retainInNavGraph to scope instances to a NavGraph.
Copyright 2019 Marcello Galhardo
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Retained is a lightweight Kotlin Multiplatform library built on top of AndroidX ViewModel. It provides a unified API to retain object instances across Kotlin Multiplatform targets.
ViewModel inheritance.ViewModelProvider.Factory.ViewModel properties: CoroutineScope (viewModelScope), SavedStateHandle, and parameters.AutoCloseable.dependencies {
// Core Kotlin Multiplatform support
implementation 'dev.marcellogalhardo:retained-core:{Tag}'
// `Activity` support
implementation 'dev.marcellogalhardo:retained-activity:{Tag}'
// `Fragment` support (includes `Activity` support)
implementation 'dev.marcellogalhardo:retained-fragment:{Tag}'
// Navigation support
implementation 'dev.marcellogalhardo:retained-navigation:{Tag}'
// Navigation with Fragment support (includes `Navigation` support)
implementation 'dev.marcellogalhardo:retained-navigation-fragment:{Tag}'
// Compose support (Android, iOS, Desktop)
implementation 'dev.marcellogalhardo:retained-compose:{Tag}'
// View support (experimental)
implementation 'dev.marcellogalhardo:retained-view:{Tag}'
implementation 'dev.marcellogalhardo:retained-navigation-view:{Tag}'
}(Replace {Tag} with the latest release version)
This section shows how to retain instances in activities and fragments. All examples use this class:
class Presenter(var counter: Int = 0)// Retain an instance in an Activity:
class CounterActivity : AppCompatActivity() {
private val presenter: Presenter by retain { Presenter() }
}
// Retain an instance in a Fragment:
class CounterFragment : Fragment() {
private val presenter: Presenter by retain { Presenter() }
}
// Share an instance between Fragments scoped to the Activity
class CounterFragment : Fragment() {
private val sharedPresenter: Presenter by retainInActivity { Presenter() }
}
// Share an instance between Fragments scoped to the NavGraph
class CounterFragment : Fragment() {
private val presenter: Presenter by retainInNavGraph(R.navigation.nav_graph) { Presenter() }
}@Composable
fun CounterScreen() {
// Scope to LocalViewModelStoreOwner (default)
val presenter = retain { Presenter() }
// Scope to ComponentActivity (Android)
val activityPresenter = retainInActivity { Presenter() }
// Scope to a specific ViewModelStoreOwner (e.g. NavBackStackEntry)
val navBackStackEntry: NavBackStackEntry // Find NavBackStackEntry
val scopedPresenter = retain(owner = navBackStackEntry) { Presenter() }
}When you retain an instance, RetainedEntry provides access to host parameters.
@Composable
fun CounterScreen() {
val presenter = retain { entry: RetainedEntry ->
Presenter()
}
// ...
}RetainedEntry provides a SavedStateHandle to save and restore state.
class CounterFragment : Fragment() {
private val presenter: Presenter by retain { entry ->
Presenter(counter = entry.savedStateHandle.get<Int>("count") ?: 0)
}
// ...
}RetainedEntry provides a CoroutineScope that matches viewModelScope.
class Presenter(scope: CoroutineScope) { /* ... */ }
class SampleFragment : Fragment() {
private val presenter: Presenter by retain { entry ->
Presenter(scope = entry.coroutineScope)
}
// ...
}For more details, see RetainedEntry.
If a retained instance implements AutoCloseable, retained automatically closes it when the host ViewModel is cleared (ViewModel.onCleared).
class ResourcePresenter : AutoCloseable {
override fun close() {
// Automatically called when the host ViewModel is cleared
}
}You can also retain instances in a View. Use these modules:
dependencies {
implementation 'dev.marcellogalhardo:retained-view:{Tag}'
implementation 'dev.marcellogalhardo:retained-navigation-view:{Tag}'
}The retained-view module provides retain and retainInActivity to scope instances to an Activity or Fragment. The retained-navigation-view module provides retainInNavGraph to scope instances to a NavGraph.
Copyright 2019 Marcello Galhardo
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.