I would think the trick is that AssistedInject gives you a factory, but ViewModelProvider.Factory is also a factory, and that Provider<MyViewModel> where applicable. But if MyViewModel has runtime arguments, then clearly Dagger won't be able to provide all of them.
When you're using AssisteInject, or pass dynamic data structures in any other hacky way, you're basically declaring that you do want to instantiate a new object and pass it some argument. In other words, you turn your composition root into a regular factory. This looks cleaner than init method on the first sight, but might blow up a bit later supper cleaner
if you discover that you need that specific service to be global. In addition, it usually requires all kinds of hacky manipulations.
Otherwise, what makes this so tricky is the overlapping responsibility of Dagger's Provider<T> and ViewModelProvider.Factory, which are both factories. So you need a factory that invokes the other factory, but you can't build Dagger's factory (without use of a subcomponent), so you need to have one generated that you can invoke inside the other one.
Now the trick here is that you can only access the runtime arguments from the enclosing scope, therefore this means that your ViewModelProvider.Factory needs to be an anonymous lambda at the time of calling... that would invoke the factory generated by @AssistedInject that is injected into the Activity/Fragment photo vault
Then the next trick is how you can access a "parametrically" instantiated ViewModel from the Fragment, if you want to access the scope from the Activity. Not sure at the moment about a way that makes sense, tbh :D maybe you need to invoke some exposed viewModel-getter-method from the Activity itself? rather than rely on the ViewModelProvider getActivity() stuff.
Generally speaking, you should avoid passing data structures into constructors. It's especially true if the data structures in question are dynamic by their nature.
I've seen some odd solutions such as "create Subcomponent so that you can @BindsInstance the runtime arguments and then construct the ViewModel at a subscope" (thus allowing the creation of a Provider<MyViewModel> from a subcomponent), I might say odd but technically that is a possible solution.
One of the goals of using DI is to hide the implementation details from the clients. The lifecycle of the injected services is also an implementation detail.
In practice, it's much cleaner and simpler to have init methods. Some developers are worried about "what will happen if I forget to call it?". Well, make sure that your application simply crashes right away in that case, so you'll know about that as quickly as possible. In my experience though, this concern isn't something that really manifests itself.