I'm not sure if I understand ViewModel architecture correctly in Android. I suppose ViewModel lifecycle is tie to the activity so we are expecting the same instance and it doesn't matter if we are passing the activity or fragment context to ViewModelProvider?
Anyway, here's my ViewModel:
class MainViewModel : ViewModel() {
var teamName: String = "Warriors";
}
Here's my Activity:
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
viewModel.teamName = "Cavaliers";
Log.d("YouQi", "activity viewModel.teamName: ${viewModel.teamName}");
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, MainFragment.newInstance())
.commitNow()
}
}
}
and lastly here's my Fragment:
class MainFragment : androidx.fragment.app.Fragment() {
companion object {
fun newInstance() = MainFragment()
}
private lateinit var viewModel: MainViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.main_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
Log.d("YouQi", "fragment viewModel.teamName: ${viewModel.teamName}");
}
}
I'm getting the below output in Logcat:
2018-06-03 16:06:24.591 31124-31124/com.axzae.zapkotlin D/YouQi: activity viewModel.teamName: Cavaliers
2018-06-03 16:06:24.652 31124-31124/com.axzae.zapkotlin D/YouQi: fragment viewModel.teamName: Warriors
It shows the value did not update to Cavaliers. am I using ViewModel wrongly and should be using Dagger to achieve singleton?
It does matter what ViewModelProvider are you using - from activity or from fragment. Please try to use ViewModelProviders.of(getActivity()) for fragment.
That's actually very handy - you can keep fragment-related model and more general activity-bound model separately.
No, you don't need to use Dependency injection to achieve singleton in ViewModel. You can pass the activity context to the ViewModel like this:
viewModel = ViewModelProviders.of(activity).get(MainViewModel::class.java)// by this you will get the same value of teamName as your activity
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With