ccd
ccd

Reputation: 6918

How to use hilt instead of using factory to init the argument in viewModel

Now I using the viewModelFactory to init the argument for viewModel in fragment.

class MyFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val binding = FragmentMyBinding.inflate(inflater)
        binding.lifecycleOwner = this
        val argument = MyFragmentArgs.fromBundle(requireArgument()).myArgument
        val viewModelFactory = MyViewModelFactory(myArgument, application)
        binding.viewModel = ViewModelProvider(
                this, viewModelFactory).get(MyViewModel::class.java)
        return binding.root
    }
}

class MyViewModelFactory(
        private val myArgument: MyArgument,
        private val application: Application) : ViewModelProvider.Factory {
    @Suppress("unchecked_cast")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
            return MyViewModel(myArgument, application) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

Compare to the hilt dependency inject way, is there a way to pass argument to viewModel directly?

Upvotes: 3

Views: 5624

Answers (2)

AliSh
AliSh

Reputation: 10619

You can do it using Hilt library. You should first define your view model by @HiltViewModel and use constructor injection(@Inject for constructor of your view model):

@HiltViewModel
class MainViewModel @Inject constructor(val foo: Foo) : ViewModel()

My Foo class is:

class Foo @Inject constructor(val someDependency: Dependency)

If you have any other class which you need to inject to your ViewModel, you can add it to your hilt module.

Finally, you should instantiate your ViewModel in your activity/fragment:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    val mainViewModel: MainViewModel by viewModels()
}

Please note that we are talking only about build time dependencies. For runtime dependencies with Hilt, you still have to stick to a classic ViewModelProvider.Factory since @AssistedInject is not yet supported by it.

Upvotes: 2

theapache64
theapache64

Reputation: 11754

Yes. With Hilt, you can completely ditch the factory pattern.

To inject a param, you can use @ViewModelInject annotation, and to inject the viewModel in the activity you can use the by viewModels() method from androidx.activity package.

Here's an example.

ProductsViewModel.kt

import androidx.hilt.lifecycle.ViewModelInject

class ProductsViewModel @ViewModelInject constructor(
    private val foo: Foo
    private val bar: Bar
) : ViewModel() 

ProductsActivity.kt

@AndroidEntryPoint
class ProductsActivity : AppCompatActivity(){
    
    val viewModel: ProductsViewModel by viewModels()
    
}

To see this in action, you can checkout this repo.

Upvotes: 2

Related Questions