Skip to content

[AssistedInject] Integration with @HiltViewModel #2287

Closed

Description

@manuelvicnt

It'd be nice to have Assisted Injection support for Hilt ViewModels.

A nice API would be something like the following:

@HiltViewModel
class PlantDetailViewModel @AssistedInject constructor(
    savedStateHandle: SavedStateHandle,
    plantRepository: PlantRepository,
    @Assisted private val plantId: String
) : ViewModel() { ... }
@AssistedFactory
interface PlantDetailViewModelFactory {
    fun create(plantId: String): PlantDetailViewModel
}

And use it from the View like:

@AndroidEntryPoint
class PlantDetailFragment : Fragment() {

    private val args: PlantDetailFragmentArgs by navArgs()

    @Inject
    lateinit var plantDetailViewModelFactory: PlantDetailViewModelFactory

    private val plantDetailViewModel: PlantDetailViewModel by viewModels {
        plantDetailViewModelFactory.create(args.plantId)
    }
}

Activity

  1. danysantiago commented on Feb 19, 2021

    @danysantiago
    Member

    Regarding Safe Args, an upcoming release of it will support parsing args from a SavedStateHandle. That should help with regards to arguments type safety.

  2. FunkyMuse commented on Feb 27, 2021

    @FunkyMuse

    How would this be done in the compose world? @manuelvicnt

  3. mhernand40 commented on Mar 12, 2021

    @mhernand40

    Isn't the example in the issue summary already possible with the latest version of Dagger and Hilt?
    Please see https://proandroiddev.com/whats-new-in-hilt-and-dagger-2-31-c46b7abbc64a#33b4

  4. Chang-Eric commented on Mar 12, 2021

    @Chang-Eric
    Member

    @mhernand40 I think the difference is that example you linked does not use @HiltViewModel which means it does not work with the ViewModelComponent. I believe it is the same as the workaround mentioned in #2287 (comment) which I have advised people not to use in #2287 (comment) due to leaking the fragment/activity instance.

  5. mhernand40 commented on Mar 12, 2021

    @mhernand40

    @Chang-Eric ah I see. I missed that subtle, yet significant detail. Thanks for bringing it to my attention. 🙂

  6. FunkyMuse commented on Mar 12, 2021

    @FunkyMuse

    @mhernand40 I think the difference is that example you linked does not use @HiltViewModel which means it does not work with the ViewModelComponent. I believe it is the same as the workaround mentioned in #2287 (comment) which I have advised people not to use in #2287 (comment) due to leaking the fragment/activity instance.

    I've read the explanation of the issue, using simple stuff like passing simple strings, ints or anything not related to a fragment/activity should be fine with the workaround suggested in the OP?

  7. Chang-Eric commented on Mar 12, 2021

    @Chang-Eric
    Member

    @FunkyMuse No, you still risk leaking the fragment/activity (even by just having a Provider<> somewhere in a transitive dep), which is not based on what you assist the factory with if you use the workaround where you inject the assisted factory into the fragment.

    Passing simple strings, ints and things are okay if you pass those through the Bundle/SavedStateHandle though.

  8. mhernand40 commented on Mar 12, 2021

    @mhernand40

    @mhernand40 I think the difference is that example you linked does not use @HiltViewModel which means it does not work with the ViewModelComponent. I believe it is the same as the workaround mentioned in #2287 (comment) which I have advised people not to use in #2287 (comment) due to leaking the fragment/activity instance.

    I've read the explanation of the issue, using simple stuff like passing simple strings, ints or anything not related to a fragment/activity should be fine with the workaround suggested in the OP?

    Agreed. Sometimes there are cases where an Intent argument is first passed to an Activity that needs to be propagated through to the ViewModel. During a configuration change, the Intent arguments should remain intact, hence there is probably no need to re-bind the argument(s) to the ViewModel?

  9. FunkyMuse commented on Mar 12, 2021

    @FunkyMuse

    @FunkyMuse No, you still risk leaking the fragment/activity (even by just having a Provider<> somewhere in a transitive dep), which is not based on what you assist the factory with if you use the workaround where you inject the assisted factory into the fragment.

    Passing simple strings, ints and things are okay if you pass those through the Bundle/SavedStateHandle though.

    That works for fragment/activity, would the same work for the compose world?

    Since there you'd still have arguments to pass but usually they're passed inside a compose function and then you create the view model

    Currently this is how I'm doing it

    @PublishedApi
    internal inline fun <reified T : ViewModel> createAssistedViewModel(
        arguments: Bundle? = null,
        owner: SavedStateRegistryOwner,
        crossinline viewModelProducer: (SavedStateHandle) -> T,
    ) =
        object : AbstractSavedStateViewModelFactory(owner, arguments) {
            override fun <T : ViewModel> create(
                key: String,
                modelClass: Class<T>,
                handle: SavedStateHandle
            ) =
                viewModelProducer(handle) as T
        }
    
    
    @Composable
    inline fun <reified T : ViewModel> assistedViewModel(
        arguments: Bundle? = null,
        crossinline viewModelProducer: (SavedStateHandle) -> T,
    ): T =
        viewModel(factory = createAssistedViewModel(
            arguments = arguments,
            owner = LocalSavedStateRegistryOwner.current
        ) {
            viewModelProducer(it)
        })
    

    Since the factory has to be injected in the activity, i assume activity has a chance of leaking?

    Any alternative solution?

  10. drinkthestars commented on Mar 14, 2021

    @drinkthestars

    The issue with the workaround is that the assisted factory is injected from the FragmentComponent (since it is injected directly into the fragment). This is a problem because it basically all but guarantees you're going to leak your activity/fragment instance into the ViewModel. This can happen simply by injecting the wrong thing into the ViewModel, but even if you are diligent about that, there's also the issue of multibinding contributions installed in the FragmentComponent. Finally, if you use fastInit mode (which is the default in Hilt), any reference to a Provider<> in the transitive deps of your ViewModel will leak the component, which will include the fragment instance (https://dagger.dev/dev-guide/compiler-options).

    No, you still risk leaking the fragment/activity (even by just having a Provider<> somewhere in a transitive dep), which is not based on what you assist the factory with if you use the workaround where you inject the assisted factory into the fragment.

    @Chang-Eric Trying to get a deeper understanding where the potential memory leak comes from with OP's workaround.
    Going through your comments, the Activity/Fragment could be leaked when:

    1. "injecting the wrong thing into the ViewModel"
    2. "having a Provider<> somewhere in a transitive dep"

    Even if those points are handled, you mention there's also the issue of multibinding contributions installed in the FragmentComponent, implying there's something inherently wrong with the very idea of "injecting assisted factory from the FragmentComponent". Could you elaborate? 🙏🏼

  11. ReginFell commented on Mar 15, 2021

    @ReginFell

    parsing args from a SavedStateHandle

    Do you have any ideas when it will be shipped?

  12. FunkyMuse commented on Mar 15, 2021

    @FunkyMuse

    parsing args from a SavedStateHandle

    Do you have any ideas when it will be shipped?

    It's already there, you pass the State handle with @HiltViewModel
    And you have access to the

    SavedStateHandle
    And
    Application

  13. Chang-Eric commented on Mar 15, 2021

    @Chang-Eric
    Member

    @drinkthestars I think the issue is just that even if you address 1 and 2 at the time you first introduce the ViewModel injection, it just isn't going to be durable as code changes without a lot of care and effort. Generally, a binding in the FragmentComponent should be free to inject the Fragment as a dependency, but if you inject your ViewModels using the workaround from the FragmentComponent, then every time you change a FragmentComponent dependency you will need to check all of the users up the chain.

    This is what Dagger components actually do for you. It is why it is nice to split say the ApplicationComponent from the ActivityComponent so that if you use the Activity from an @Singleton binding, you get a missing binding error instead of a memory leak. In Hilt, the components are also set up to prevent this for ViewModels (in https://dagger.dev/hilt/components, you can see how the ViewModelComponent branches off before the ActivityComponent and FragmentComponent). If you use the workaround, then you'll subvert this.

  14. drinkthestars commented on Mar 15, 2021

    @drinkthestars

    Gotcha, thank you for clarifying @Chang-Eric. So the case seems to be:

    @HiltViewModel's ensures that there is an associated with ViewModelComponent which reflects the lifetime of the single ViewModel. If ViewModels are injected using the AssistedFactory workaround from the FragmentComponent, you end up associating a ViewModel related thing with a FragmentComponent which has a shorter lifecycle than a ViewModel/ViewModelComponent. The workaround is mixing two hierarchies of components where one should outlive the other, and hence it is not recommended.

  15. ottne commented on Mar 17, 2021

    @ottne

    This absolutely should be supported. Injecting ViewModels/Presenters is one of the primary use cases of AssistedInjection on Android.

  16. hichamboushaba commented on Apr 21, 2021

    @hichamboushaba

    If the main reason for assisted injection is just passing arguments, then as others pointed, SavedStateHandle has them, and starting with version 2.4.0 of the navigation library, we'll get a way to retrieve safe args from it.
    As a temporary workaround, I'm using this extension:

    inline fun <reified Args : NavArgs> SavedStateHandle.navArgs() = NavArgsLazy(Args::class) {
        val bundle = Bundle()
        keys().forEach {
            val value = get<Any>(it)
            if (value is Serializable) {
                bundle.putSerializable(it, value)
            } else if (value is Parcelable) {
                bundle.putParcelable(it, value)
            }
        }
        bundle
    }

    to create the corresponding Args class, and I use it in the viewmodel like this:

    val args: YourFragmentArgs by savedState.navArgs()

    where savedState is the inject SavedStateHandle

  17. ReginFell commented on Apr 30, 2021

    @ReginFell

    If the main reason for assisted injection is just passing arguments, then as others pointed, SavedStateHandle has them, and starting with version 2.4.0 of the navigation library, we'll get a way to retrieve safe args from it.
    As a temporary workaround, I'm using this extension:

    inline fun <reified Args : NavArgs> SavedStateHandle.navArgs() = NavArgsLazy(Args::class) {
        val bundle = Bundle()
        keys().forEach {
            val value = get<Any>(it)
            if (value is Serializable) {
                bundle.putSerializable(it, value)
            } else if (value is Parcelable) {
                bundle.putParcelable(it, value)
            }
        }
        bundle
    }

    to create the corresponding Args class, and I use it in the viewmodel like this:

    val args: YourFragmentArgs by savedState.navArgs()

    where savedState is the inject SavedStateHandle

    This approach has a caveat, with bundle it would not be possible to unit test viewModels that have args

  18. alizarei95 commented on May 31, 2021

    @alizarei95

    Is there any plan to support AssistedInject in ViewModel?

  19. Chang-Eric commented on Jun 1, 2021

    @Chang-Eric
    Member

    Is there any plan to support AssistedInject in ViewModel?

    We've looked into it, but it isn't trivial and so far the API wouldn't be that great. This doesn't mean it is off the table, but it also isn't a high priority compared to other things so I wouldn't expect it anytime in the near future.

  20. alizarei95 commented on Jun 2, 2021

    @alizarei95

    Is there any plan to support AssistedInject in ViewModel?

    We've looked into it, but it isn't trivial and so far the API wouldn't be that great. This doesn't mean it is off the table, but it also isn't a high priority compared to other things so I wouldn't expect it anytime in the near future.

    according to requests in this topic I think assisted inject in viewmodel is a common use case

  21. nathan815 commented on Jul 12, 2021

    @nathan815

    @hichamboushaba That is nice, but makes testing the ViewModel difficult. Did you find a way to write unit tests for a ViewModel with this?

    I really prefer the ViewModel to take in real arguments in the constructor but this is apparently not possible to do correctly with Hilt currently.

  22. hichamboushaba commented on Jul 12, 2021

    @hichamboushaba

    @hichamboushaba That is nice, but makes testing the ViewModel difficult. Did you find a way to write unit tests for a ViewModel with this?

    I really prefer the ViewModel to take in real arguments in the constructor but this is apparently not possible to do correctly with Hilt currently.

    For tests, you can always pass your copy of SavedStateHandle that you can use for the logic, either by manually creating it using argument keys, or by leveraging the toBundle method, the issue is that like others mentioned, we will depend on Bundle for the tests, so for now, and until the version 2.4.0 of navigation component is released, we depend on Robolectric for the unit tests, and as far as it's temporary, we as a team agreed it's not a blocker.

    To init SavedStateHandle from our NavArgs class, we use the following extensions in tests:

    fun NavArgs.initSavedStateHandle(): SavedStateHandle {
        val toBundleMethod = javaClass.getDeclaredMethod("toBundle")
        val bundle = toBundleMethod.invoke(this) as Bundle
        val argumentsMap = bundle.keySet().map { it to bundle[it] }.toMap()
        return SavedStateHandle(argumentsMap)
    }
  23. patriotic commented on Aug 3, 2021

    @patriotic

    Getting ViewModel constructor should be annotated with @Inject instead of @AssistedInject with version 2.38.1

  24. Chang-Eric commented on Aug 5, 2021

    @Chang-Eric
    Member

    @patriotic That's expected. @HiltViewModel only works with @Inject right now as this currently open issue is for adding support for @AssistedInject.

  25. danielesegato commented on Oct 8, 2021

    @danielesegato

    @Chang-Eric

    The main workaround we suggest is to use the arguments bundle in your fragment which should be accessible via the SavedStateHandle injected in the ViewModel. This should handle most data types.

    For other object types, hopefully rarer, I think the options are passing them as arguments when calling methods on the ViewModel or using a setter method (though similarly, be careful of leaks in this case, especially with any function closures as those may reference the fragment).

    I get you have other priorities, but I believe AssistedInject is important.

    Is there any plan to support AssistedInject in ViewModel?

    We've looked into it, but it isn't trivial and so far the API wouldn't be that great. This doesn't mean it is off the table, but it also isn't a high priority compared to other things so I wouldn't expect it anytime in the near future.

    You mentioned it is trivial to do. I don't think it's trivial to most people using Hilt / Dagger.

    May I ask you to provide examples of both of these?
    Thanks.

  26. Chang-Eric commented on Oct 8, 2021

    @Chang-Eric
    Member

    @danielesegato It is half priorities, half that we haven't found the right API for this. We plan to look into the API again after https://issuetracker.google.com/188541057 is resolved as that will solve some of the API problems we're running into. This is lower priority because there are workarounds like using the SavedStateHandle (which is probably a best practice over AssistedInject because it cannot leak the activity/fragment) and for those things that cannot be put in the bundle, you can use a setter method (obviously not ideal from a code cleanliness perspective, but this case should be rarer). Do you have a case that cannot be addressed with these workarounds?

    We've looked into it, but it isn't trivial and so far

    You mentioned it is trivial to do

    I don't think I said it was trivial unless you're referring to something else that you didn't quote. In fact I thought I said it is not trivial?

  27. danielesegato commented on Feb 2, 2022

    @danielesegato

    We plan to look into the API again after https://issuetracker.google.com/188541057 is resolved as that will solve some of the API problems we're running into.

    Hi @Chang-Eric do you have any update? the issue has been marked fixed in October of 2021 and this github issue is linked in the official doc on hilt on how to "officially" handle assisted parameters in viewmodels: https://developer.android.com/training/dependency-injection/hilt-jetpack

    This is lower priority because there are workarounds like using the SavedStateHandle (which is probably a best practice over AssistedInject because it cannot leak the activity/fragment) and for those things that cannot be put in the bundle, you can use a setter method (obviously not ideal from a code cleanliness perspective, but this case should be rarer).

    I still think I should be able to use @HiltViewModel with @AssistedInject.

    the @AssistedFactory could than be used with by viewModelFactory(Factory::class).viewModel(...parameters...) or by viewModelFactory(Factory::class).activityViewModel(...parameters...)`

    there should a lambda somewhere there to avoid re-executing parameter creation if not needed

    Thanks.

  28. Chang-Eric commented on Feb 3, 2022

    @Chang-Eric
    Member

    Sorry, I don't have any real update at this time. We're focusing on KSP migrations for Dagger so that is taking a lot of our time right now so this is still a lower priority. Also, I think that necessary fix is still only in alpha, so we can't depend on it yet since Hilt is stable.

    Also, there's still some uncertainty about the direction we want to take the API. ViewModels do not compose together well, so there are some questions about if use cases would be better served with more things like ActivityRetainedComponent but for other lifetimes since then Dagger objects in there can compose better and don't have the same leaking risks that @AssistedInject into ViewModels presents. That's not to commit one way or another, but just to let you know that even if all the immediate blockers are resolved, this isn't a clear cut case where we just need to find the time to put some code together.

    Hope that makes sense, and sorry this probably isn't the update you were looking for.

  29. danielesegato commented on Feb 3, 2022

    @danielesegato

    I see what you mean, I don't really like that you can't inject a ViewModel into another viewModel, makes it harder to create separation of concerns.

    But Hilt can't really fix that: something has to be done from the Androidx side with ViewModel replacement / upgrade.

  30. syt0r commented on Jun 21, 2022

    @syt0r

    For the first time I've decided to use Hilt instead of Koin and it's very disappointing that support of already existing feature takes so long...

  31. EllenMady commented on Jul 1, 2022

    @EllenMady

    @wbervoets With the new @HiltViewModel you can have the SavedStateHandle as a dependency without having to annotate it with @Assisted. The SavedStateHandle is now a binding from the new ViewModelComponent, so it doesn't need to be assist-injected anymore.

    Man, you saved my life. I'm using compose navigation and I send runtime parameters throw SavedSateHandle like you said. Nothing more is need. Thanks a lot!

  32. sebaslogen commented on Aug 26, 2022

    @sebaslogen

    Now that we can inject multiple ViewModel instances of the same type (#2328) inside the same Composable nav-destination/screen (for example for a View-Pager) I really miss the Assisted Injection to provide unique ids to each ViewModel.

    Unfortunately, SavedStateHandle solution can't help in this situation because the navArgs only work at the Composable nav-destination/screen level, and in this use case the multiple ViewModel ids are only available after the Composable nav-destination/screen is loaded (probably through a screen level ViewModel that loads the ids of the View-Pager ViewModels).

  33. mkalitis commented on Sep 29, 2022

    @mkalitis

    @manuelvicnt This is getting a little confusing given the length of the thread, lets see if I have this correctly.

    We are trying to 'inject' the parameters passed during navigation directly to the view model whilst still having the goodness provided to us with the @HiltViewModel annotation yes?

    If so then we do not need the hassle of creating a factory etc nor do we need the @Assisted for the injection. Further we also do not need to pass in the parameter to the screen/fragment which then passes it to the view model. Hilt already gives us this functionality.

    I think I might be missing something here??

    Thanks,

    Martin

  34. svenjacobs commented on Sep 29, 2022

    @svenjacobs

    I'm also looking forward to assisted injection for ViewModels. Given the stance "favour composition over inheritance", I would like to inject some "behavioural" pattern into the constructor of a VM which is only known at instantiation time. SavedStateHandle doesn't help here because this class cannot be put into a Bundle.

  35. Tgo1014 commented on Jan 27, 2023

    @Tgo1014

    Really missing this feature, I tried to use the new ViewModelLifecycleScope {} with hiltViewModel() but unfortunately it crashes. Would help a lot for having different instances in a ViewPager with the same screen working independently.

  36. mecoFarid commented on Feb 13, 2023

    @mecoFarid

    Is there any plan to support AssistedInject in ViewModel?

    We've looked into it, but it isn't trivial and so far the API wouldn't be that great. This doesn't mean it is off the table, but it also isn't a high priority compared to other things so I wouldn't expect it anytime in the near future.

    You mean like for the next 15 years?

  37. JohannesPtaszyk commented on Feb 14, 2023

    @JohannesPtaszyk

    Are there any updates/plans? :)
    Would be really handy to get this!

  38. Chang-Eric commented on Mar 8, 2023

    @Chang-Eric
    Member

    Just updating this. We have a plan for supporting this now, however, it is competing with other higher priority projects for development time like the migration to KSP, so there's no real timeline here yet.

    FWIW, now that CreationExtras is supported, you can use the DEFAULT_ARGS_KEY key for setting the default args passed to a ViewModel's SavedStateHandle, so you don't have to only pass things through the Fragment arguments. So something like:

    val myVM by viewModels<MyViewModel>(extrasProducer = {
      MutableCreationExtras(defaultViewModelCreationExtras).apply {
        set(DEFAULT_ARGS_KEY, bundleOf("someId" to someId))
      }
    })

    will let you pass a value to be retrieved in the ViewModel through the SavedStateHandle.

  39. mtwalli commented on Mar 10, 2023

    @mtwalli

    A good improvement on top of the workaround is to define a few extensions to generalize the solution so we don't need to repeat that boilerplate in each ViewModel. Here's the example for the fragment scoped ViewModel case:

    inline fun <reified T : ViewModel> Fragment.assistedViewModel(
      crossinline viewModelProducer: (SavedStateHandle) -> T
    ) = viewModels<T> {
      object : AbstractSavedStateViewModelFactory(this, arguments) {
        override fun <T : ViewModel> create(key: String, modelClass: Class<T>, handle: SavedStateHandle) =
          viewModelProducer(handle) as T
      }
    }

    And then in the fragment:

    @Inject lateinit var viewModelFactory: SomeViewModel.Factory
    
    private val viewModel by assistedViewModel { 
      viewModelFactory.create(input = args.input, savedStateHandle = it)
    }

    Other extensions can then be added to cover the other cases.

    It would definitely be better to have Hilt support this out of the box, though, and I really like the API suggested here.

    How possibly this solution could be working in unit tests?

  40. mkalitis commented on Mar 10, 2023

    @mkalitis

    A similar thing can already be done using annotation classes which use the navigation parameters to "assist" the additional parameters into the viewmodel constructor when using HiltViewModel() This gives the same behaviour as doing an @assisted on the view model. This works for something like compose navigation though could be extended to other screen creation/fragment creation.

    More info here: https://medium.com/@i.write.code/android-compose-navigation-view-models-and-hilt-c824541bd8e
    Example code of doing this with compose navigation: https://github.com/mkalitis/HiltNavigationInjection

    Just an thought

  41. nvkleban commented on Nov 9, 2023

    @nvkleban

    Dagger documentation shows currently not released APIs like HiltViewModelExtensions.withCreationCallback is this the solution we were waiting for?

  42. ubuntudroid commented on Nov 9, 2023

    @ubuntudroid

    Dagger documentation shows currently not released APIs like HiltViewModelExtensions.withCreationCallback is this the solution we were wainitng for?

    Exciting! Hopefully this will also work with hiltViewModel() in Compose.

  43. kuanyingchou commented on Nov 9, 2023

    @kuanyingchou

    @nvkleban @ubuntudroid This should be out in the next release, and hiltViewModel() will be updated next. In the meantime you can give HEAD-SNAPSHOT a try to see if it works for you!

  44. armichaud commented on Jan 19, 2024

    @armichaud

    For those who might be reading this thread looking for how in the end this works with hiltViewModel(), here's a guide.

  45. cgaisl commented on Jan 20, 2024

    @cgaisl

    I've shared my journey of trying to pass runtime arguments to a @hiltviewmodel here.

  46. carstenhag commented on Feb 26, 2024

    @carstenhag

    @kuanyingchou This ticket can also be closed, right? It is mentioned in the release notes as fixed

  47. kuanyingchou commented on Feb 27, 2024

    @kuanyingchou

    @carstenhag Yes! Assisted injection with ViewModels was added in Dagger 2.49 and overloads for functions like hiltViewModel() were added to the AndroidX part of Hilt in 1.2.0. Thanks for the reminder!

  48. myounis97 commented on Feb 29, 2024

    @myounis97

    How can I inject SavedStateHandle with the new approach I used to inject it like in the screenshot is there a way to migrate to the new approach
    Screenshot 2024-02-29 121950
    ?

  49. tfcporciuncula commented on Feb 29, 2024

    @tfcporciuncula

    @myounis97 As it's mentioned here, SavedStateHandle is a binding from ViewModelComponent so you can add it as a regular non-assisted dependency to your ViewModel if you're using Hilt.

  50. myounis97 commented on Feb 29, 2024

    @myounis97

    @myounis97 As it's mentioned here, SavedStateHandle is a binding from ViewModelComponent so you can add it as a regular non-assisted dependency to your ViewModel if you're using Hilt.

    Unfortunately it doesn't work with @hiltviewmodel(assistedFactory) it gives compile time error cannot inject savedStateHandle without @provide

  51. tfcporciuncula commented on Feb 29, 2024

    @tfcporciuncula

    This compiles fine for me:

    @HiltViewModel(assistedFactory = MyViewModel.Factory::class)
    class MyViewModel @AssistedInject constructor(
      @Assisted val runtimeArg: String,
      private val savedStateHandle: SavedStateHandle,
      private val someDependency: SomeDependency,
    ) : ViewModel() {
      @AssistedFactory interface Factory {
        fun create(runtimeArg: String): MyViewModel
      }
      ...
    }

    And I'm able to create the ViewModel with:

    private val myViewModel by viewModels<MyViewModel>(
      extrasProducer = {
        defaultViewModelCreationExtras.withCreationCallback<MyViewModel.Factory> { factory ->
          factory.create(runtimeArg = "abc")
        }
      }
    )

    As it's described in the docs.

  52. myounis97 commented on Feb 29, 2024

    @myounis97

    @tfcporciuncula My bad i didn't remove the factory from the Singleton Scoped Entry point after removing it everything worked fine thanks

    Screenshot 2024-02-29 141727

  53. Zhuinden commented on Feb 17, 2025

    @Zhuinden

    Just making sure these two issues are related via links #3523 (comment)

  54. iamanbansal commented on Jun 19, 2025

    @iamanbansal

    Facing Dagger does not support providing @AssistedFactory types. while writing Fragment/Activity test. What's the right way to provide factory ?
    @manuelvicnt @tfcporciuncula

    @HiltAndroidTest
    class FragmentTest {
    
        @RelaxedMockK
        lateinit var viewmodel:HubViewModel
    
        @BindValue
        val hubViewModelAssistedFactory = object : HubViewModelAssistedFactory {
            override fun create(flowProvider: Provider): HubViewModel {
                return viewmodel
            }
        }
    
  55. Chang-Eric commented on Jun 20, 2025

    @Chang-Eric
    Member

    @iamanbansal You can't bind over the AssistedFactory binding, even in tests, as that is something Hilt is passing to your callback. In general, we don't support providing a fake ViewModel, but rather encourage changing the bindings the ViewModel depends on in tests.

  56. iamanbansal commented on Jun 20, 2025

    @iamanbansal

    Thanks @Chang-Eric ! I can change other bindings of VM but how would I change the binding of assisted one (provider in my case) in test case? Currently real object is being passed from the Fragment.
    It would be great if there is any example of Fragment/Activity Test for such Assisted Injection

  57. Chang-Eric commented on Jun 23, 2025

    @Chang-Eric
    Member

    @iamanbansal Assisted parameters are passed from your code and not from Dagger/Hilt so there's nothing we really provide here. Those parameters are kind of outside of dependency injection so you'd have to figure out your own strategy to handle the arguments like any other argument you pass into a normal method.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions