• Stars
    star
    323
  • Rank 130,051 (Top 3 %)
  • Language
    Kotlin
  • License
    Apache License 2.0
  • Created almost 5 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

[ACTIVE] A lightweight alternative to Android's ViewModels. The easiest way to retain instances in Activities, Fragments or Composables.

Retained Instance

A lightweight library built on top of Android Architecture Component ViewModel to simplify how UI Controllers (e.g., Activity, Fragment & NavBackStackEntry) retain instances on Android.

  • Eliminate ViewModel inheritance.
  • Eliminate ViewModelProvider.Factory need.
  • Easy access to ViewModel scoped properties: CoroutineScope (viewModelScope), SavedStateHandle, and many others.
  • Enable composition: callbacks can be listened with OnClearedListener.

Motivation: Retained was originally created to share a ViewModel in Kotlin Multiplatform projects between Android & iOS with ease.

Download

dependencies {
    // `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
    implementation 'dev.marcellogalhardo:retained-compose:{Tag}'
    
    // View support (experimental)
    implementation 'dev.marcellogalhardo:retained-view:{Tag}'
    implementation 'dev.marcellogalhardo:retained-navigation-view:{Tag}'
}

(Please replace {Tag} with the latest version numbers)

Usage

The following sections demonstrate how to retain instances in activities and fragments. For simplicity, all examples will retain the following class:

class ViewModel(var counter: Int = 0)

Use Retained in Activities and Fragments

// retain an instance in an Activity:
class CounterActivity : AppCompatActivity() {
    private val viewModel: ViewModel by retain { ViewModel() }
}

// retain an instance in a Fragment:
class CounterFragment : Fragment() {
    private val viewModel: ViewModel by retain { ViewModel() }
}

// share an instance between Fragments scoped to the Activity
class CounterFragment : Fragment() {
    private val sharedViewModel: ViewModel by retainInActivity { ViewModel() }
}

// share an instance between Fragments scoped to the NavGraph
class CounterFragment : Fragment() {
    private val viewModel: ViewModel by retainInNavGraph(R.navigation.nav_graph) { ViewModel() }
}

Compose Support

@Composable
fun SampleView() {
    val viewModel = retain { ViewModel() }
    
    val activity: ComponentActivity // find Activity
    val viewModel = retain(owner = activity) { ViewModel() }
    
    val fragment: Fragment // find Fragment
    val viewModel = retain(owner = fragment) { ViewModel() }
    
    val navBackStackEntry: NavBackStackEntry // find NavBackStackEntry
    val viewModel = retain(owner = navBackStackEntry) { ViewModel() }
}

Advanced usage

Custom parameters from Jetpack's ViewModel

When retaining an instance, you have access to a RetainedEntry which contains all parameters you might need.

@Composable
fun SampleView() {
    val viewModel = retain { entry: RetainedEntry ->
        ViewModel()
    }
    // ...
}

The entry exposes a SavedStateHandle that can be used to work with the saved state, just like in a regular Android ViewModel.

class CounterFragment : Fragment() {
    private val viewModel: ViewModel by retain { entry -> 
        ViewModel(counter = entry.savedStateHandle.get<Int>("count"))
    }
    // ...
}

It also exposes a CoroutineScope that works just like viewModelScope from the Android ViewModel.

class Presenter(scope: CoroutineScope) { /* ... */ }

fun SampleFragment() {
    private val presenter: Presenter by retain { entry -> 
        Presenter(scope = entry.scope)
    }
    // ...
}

For more details, see RetainedEntry.

Listening onCleared calls

When retaining an instance, you can use the RetainedEntry to be notified when a retained instance is cleared (ViewModel.onCleared).

@Composable
fun SampleView() {
    val viewModel = retain { entry ->
        entry.onClearedListeners += {
            println("Invoked when the host 'ViewModel.onCleared' is called")
        }
        // ...
    }
    // ...
}

As a convenience, if the retained instance implements the OnClearedListener interface, it will be automatically added to onClearedListeners and notified.

View support (experimental)

Besides Activities and Fragments, it's also possible to retain instances in a view. There are a couple of extra modules for that:

dependencies {
    implementation 'dev.marcellogalhardo:retained-view:{Tag}'
    implementation 'dev.marcellogalhardo:retained-navigation-view:{Tag}'
}

The retained-view module exposes retainInActivity and retain, which will scope the instance to the parent being it an activity or a fragment. The retained-view-navigation module exposes retainInNavGraph to retain instances scoped to the NavGraph.

License

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.

More Repositories

1

android-challenge

Android Engineer Challenge for Guidebook.
Java
181
star
2

hilt-to-anvil

Sample Dagger setup using Anvil to simulate Hilt features.
Kotlin
39
star
3

kotlin-fixture

[Deprecated] Fixture is an open source library designed to make it easier to create object graphs containing test data.
Kotlin
26
star
4

android-blanket

[Deprecated] Blanket is a ​simple library to help you bind your views and use a fluent interface to ​access their methods. No boilerplate code, I ​promise.
Java
12
star
5

android-challenge-mobicare

Android Engineer Challenge for Mobicare.
Java
11
star
6

android-simple-settings

[Deprecated] Easy and fast server configuration manager.
Java
10
star
7

staccato

A lightweight state management library for Compose.
Kotlin
5
star
8

android-challenge-goconqr

Android Engineer Challenge for GoConqr.
Java
5
star
9

android-condufacil

Java
4
star
10

android-challenge-concrete

Android Engineer Challenge for Concrete.
Java
2
star
11

android-challenge-belly

Android Engineer Challenge for Belly.
CMake
2
star
12

csharp-rest-builder

[Deprecated] Classe simples para utilizar o padrão Builder na lib RestSharp (https://github.com/restsharp/RestSharp).
C#
2
star
13

anvil-missing-modules

Kotlin
1
star
14

marcellogalhardo.github.io

HTML
1
star
15

android-challenge-quandoo

Android Engineer Challenge for Quandoo.
Java
1
star
16

android-gecko

Java
1
star
17

bur-report-dexter-black-screen

Repository create to report a Bug on Dexter Library.
Java
1
star
18

kotlin-gilded-rosa-kata

Starting code for the GildedRose Refactoring Kata in Kotlin.
Kotlin
1
star
19

android-lynx

Java
1
star