'How to pass arguments from Activity to ViewModel using Hilt (without a ViewModel Factory)

In my activity, I have multiple variables being initiated from Intent Extras. As of now I am using ViewModelFactory to pass these variables as arguments to my viewModel.

How do I eliminate the need for ViewModelFacotory with hilt

Here are two variables in my Activity class

class CommentsActivity : AppCompatActivity() {

    private lateinit var viewModel: CommentsViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        val contentId = intent.getStringExtra(CONTENT_ID_FIELD) //nullable strings
        val highlightedCommentId = intent.getStringExtra(HIGHLIGHTED_COMMENT_ID_RF) //nullable strings
        
        val commentsViewModelFactory = CommentsViewModelFactory(
            contentId,
            highlightedCommentId
        )

         viewModel = ViewModelProvider(this, commentsViewModelFactory[CommentsViewModel::class.java]


    }
}

Here is my viewModel

class CommentsViewMode(
    contentId : String?,
    highlightedCo;mmentId : String?,
) : ViewModel() {

    //logic code here 

}

My app is already set up to use hilt but in this case How can I pass these 2 variables and eliminate the viewModelFactory entirely



Solution 1:[1]

The trick is to initialize those variables only once, while the activity can be created multiple times. In my apps, I use a flag.

View model:

class CommentsViewModel : ViewModel() {

    private var initialized = false

    private var contentId : String? = null
    private var highlightedCommentId : String? = null
    
    fun initialize(contentId : String?, highlightedCommentId : String?) {
        if (!initialized) {
            initialized = true
            this.contentId = contentId
            this.highlightedCommentId = highlightedCommentId
        }
    }
    //logic code here 

}

Also, you should know that there is an open issue in dagger project exactly for this capability: https://github.com/google/dagger/issues/2287

You're welcome to follow the progress.

Solution 2:[2]

If you want to use hilt effectively u can follow this steps Use @HiltViewModel in your view model

@HiltViewModel
class MyViewModel @inject constructor(private val yrParameter): ViewModel {}

Also you no longer need any ViewModelFactory! All is done for you! In your activity or fragment, you can now just use KTX viewModels() directly.

private val viewModel: MyViewModel by viewModels()

Or if you want to use base classes for fragment and activity you can use this code to pass viewModel class

abstract class BaseFragment<V: ViewModel, T: ViewDataBinding>(@LayoutRes val layout: Int, viewModelClass: Class<V>) : Fragment() {
    
      private val mViewModel by lazy {
            ViewModelProvider(this).get(viewModelClass)
        }
    
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Mojtaba Shirkhani