I am trying to pass a constructor parameter in the ViewModel class. But I don't understand the best approach to do this. Please take a look at the code and comment and let me know the easiest and appropriate way.
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
// Question 1: How can I pass constructor parameter if I use this delegate feature?
// private lateint var viewModel: MainViewModel by viewModels()
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val repository = Repository()
// Passing constructor directly works.
viewModel = MainViewModel(repository)
// Question 2: Why do I need this factory class / method as it works without these two lines.
// val viewModelFactory = MainViewModelFactory(repository)
// viewModel = ViewModelProvider(this, viewModelFactory).get(MainViewModel::class.java)
viewModel.getPost()
viewModel.mResponse.observe(this, Observer { response ->
if (response.isSuccessful) {
Log.d("Response: ", response.body()?.userId.toString())
Log.d("Response: ", response.body()?.id.toString())
binding.textView.text = response.body()?.title.toString()
Log.d("Response: ", response.body()?.body.toString())
} else {
Log.d("Response: ", response.errorBody().toString())
binding.textView.text = response.code().toString()
}
})
}
}
CodePudding user response:
Here is another thread on this topic Why a viewmodel factory is needed in Android?
A ViewModelFactory is used to create the ViewModel if it requires additional arguments beyond the basic constructor.
The purpose is separation of concerns, you should not be instantiating a ViewModel in the Activity because then the Activity has to know about all the parameters the ViewModel requires. The goal is to keep your view code as dumb as possible, so keeping references to data layer code and business logic in your Activity is not a good idea. Ex: Repository
Additionally a ViewModelProvider allows you to share a single instance of a ViewModel between Activities and Fragments if you want, this can let you maintain state in multiple places without passing data around.
Here's an android develop course about MVVM, it includes a lesson about how to properly use a ViewModelFactory https://developer.android.com/codelabs/kotlin-android-training-view-model#7
CodePudding user response:
// Question 1: How can I pass constructor parameter if I use this delegate feature?
// private lateint var viewModel: MainViewModel by viewModels()
You would pass your ViewModelFactory
as a parameter to viewModels()
. Or, depending on the nature of the parameter, use a dependency inversion framework (Dagger/Hilt, Koin, etc.). In your case, you seem to be passing some sort of repository, in which case a dependency inversion framework is a popular solution.
// Question 2: Why do I need this factory class / method as it works without these two lines.
Because it does not actually work. In particular, that MainViewModel
instance does not survive a configuration change (e.g., screen rotation). If you want to use the Jetpack ViewModel
system correctly, the ViewModel
system has to instantitate your MainViewModel
.