Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Lifecycle-2.5.0 and review internal ViewModel design #1380

Closed
marcellogalhardo opened this issue Jul 8, 2022 · 4 comments
Closed

Use Lifecycle-2.5.0 and review internal ViewModel design #1380

marcellogalhardo opened this issue Jul 8, 2022 · 4 comments

Comments

@marcellogalhardo
Copy link
Contributor

marcellogalhardo commented Jul 8, 2022

The following feature request is a proposal, and my idea is to open a discussion on how we can use the new Lifecycle-2.5.0 and simplify the Koin ViewModel support. The proposed changes will introduce a breaking change but should better align Koin's implementation with Android X's one.

Is your feature request related to a problem? Please describe.

Our current ViewModel support has a few problems (see here), specifically when dealing with SavedStateHandle.

Describe the solution you'd like

With Lifecycle-2.5.0, we have access to new functions that facilitate the creation of ViewModels. It would be wise to refactor the current implementation to use the new stable APIs, which are more flexible and will simplify our code considerably. The new API simplifies considerably how to deal with SavedStateHandle.

Describe alternatives you've considered

The changes here will require a few steps.

  1. Update the project to use Lifecycle-2.5.0.
  2. Redesign the internals of our Koin APIs to use the new ViewModelProvider.Factory method:
public interface ViewModelProvider.Factory {
        
        public fun <T : ViewModel> create(modelClass: Class<T>): T = TODO()

        // New method, the one we will be using.
        public fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T = TODO()

With the new create method, we have access to an extras parameter that allow us to call createSavedStateHandle and other methods. In other words, we only need a ViewModelStoreOwner - no need for a SavedStateRegistryOwner. We can automatically make visible CreationExtras and SavedStateHandle to any ViewModel declared within Koin's viewModel DSL and things should work out of the box.

  1. (Optional) Consider to redesign the viewModel, sharedViewModel and getViewModel hooks, for simplification purposes and to keep it as close as possible to androidx.lifecycle.
inline fun <reified VM : ViewModel> koinViewModel(
  qualifier: Qualifier? = null,
  owner: ViewModelStoreOwner,
) = TODO()

inline fun <reified VM : ViewModel> ViewModelStoreOwner.koinViewModel(
  qualifier: Qualifier? = null,
) = koinViewModel(qualifier, this)

@Composable
inline fun <reified VM : ViewModel> koinViewModel(
  qualifier: Qualifier? = null,
) = koinViewModel(qualifier, LocalViewModelStoreOwner.current)

inline fun <reified VM : ViewModel> koinViewModels(
  qualifier: Qualifier? = null,
  owner: () -> ViewModelStoreOwner,
) = TODO()

inline fun <reified VM : ViewModel> ViewModelStoreOwner.koinViewModels(
  qualifier: Qualifier? = null,
) = koinViewModel(qualifier) { this }

As you can see, the 5 APIs can cover all cases (Activity, Fragment, Composables...) without any extra code. See below a Fragment example:

class MyFragment: Fragment() {
  val activityVm by koinViewModels<ViewModel> { requireActivity() }
  val parentVm by koinViewModels<ViewModel> { requireParentFragment() }
  val fragmentVm by koinViewModels<ViewModel>()
}

@Composable
fun MyComposable() {
  val vm = koinViewModel<ViewModel>()
}

FYI: Names are subject to change, the example is to demonstrate what the API would look like.

Target Koin project

Probably the next major version, should be discussed.

@marcellogalhardo marcellogalhardo changed the title Use Lifecycle-2.5.0 and internal ViewModel design Use Lifecycle-2.5.0 and review internal ViewModel design Jul 8, 2022
@arnaudgiuliani
Copy link
Member

Yes, I was wondering to rework it from the ground in next versions.

Do the public fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras) is called with current Android components arguments? I mean no need to pass extras by hand?

Your proposal is very good. One downward of this, is that is cuts the parametersOf capacity to let us forward argument for Koin instance creation. But yes, I'm super interested to iterate over this new ViewModel API

@arnaudgiuliani
Copy link
Member

arnaudgiuliani commented Jul 11, 2022

Ok got it:

These extras are provided automatically by your Activity or Fragment when using Activity 1.5.0 and Fragment 1.5.0, respectively.

@arnaudgiuliani arnaudgiuliani added this to the 3.3.0 milestone Aug 24, 2022
@arnaudgiuliani
Copy link
Member

I like your API Proposal. I'm looking at the new ViewModel DSLs
I'm checking right now:

  1. allow use injected parameters
  2. check creation of Factory & extras part

@arnaudgiuliani
Copy link
Member

I finally could mix both API and allow to propose either CreationExtra or Injected Parameters, depending on the need.
The full PR is #1459

All are rewired on lifecycle 2.5.1 which allows having lighter internals, and a safer way to inject SavedStateHandle params.

No more need for stateViewModel APIs. I also propose switching sharedViewModel function to activityViewModel which is more explicit. Else everything can be setup as will.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants