Androidviewmodel VS Viewmodel

AndroidViewModel vs ViewModel

AndroidViewModel provides Application context

If you need to use context inside your Viewmodel you should use AndroidViewModel (AVM), because it contains the application context. To retrieve the context call getApplication(), otherwise use the regular ViewModel (VM).

AndroidViewModel has application context.
We all know having static context instance is evil as it can cause memory leaks!! However, having static Application instance is not as bad as you might think because there is only one Application instance in the running application.

Therefore, using and having Application instance in a specific class is not a problem in general. But, if an Application instance references them, it is a problem because of the reference cycle problem.

See Also about Application Instance

AndroidViewModel Problematic for unit tests

AVM provides application context which is problematic for unit testing. Unit tests should not deal with any of the Android lifecycle, such as context.

What is the Difference between AndroidViewModel and ViewModel in Android Architecture Components?

But for AndoirdViewModel scenario I can get application context by extending a class to Application class

Creating your own custom subclass of Application does not magically make that singleton instance available to a ViewModel.

It is possible to create a custom subclass of Application that has its own getInstance() method or something to expose the singleton directly. Google does not like this pattern (and neither do I, for that matter), and so Google does not steer developers towards using it.

What is the actual difference between them in Android Development?

A ViewModel on its own has no good way to get a Context. AndroidViewModel supplies an Application for use as a Context, and specifically supplies the Application singleton so we are sure that the Context itself does not represent a memory leak.

AndroidViewModel vs passing Application context to ViewModel

If you're providing your own factory, you can pass anything you want to a regular ViewModel object, you're correct about that.

However, if you are using the default factories, the source code shows that the default factories only fill in the Application instance for you if your ViewModel extend AndroidViewModel.

whats the difference between viewModel and viewModels class

You compare kotlin delegate function( by viewModels()) and ViewModel class together, open sources i think that will help you better understand.

Why using AndroidViewModel?

Not all codebases are created equal. AndroidViewModel can be a useful tool for incremental refactoring in "legacy" codebases that don't have many abstractions or layering in place (read: Activity/Fragment god objects).

As a bridge from a "legacy" codebase, it makes sense to use it in this situation.

  1. But why would one do this? It hurts me to see application handed over to ViewModel. What would be an acceptable use case for this?

The use case for AndroidViewModel is for accessing the Application. In a "legacy" codebase, it's relatively safe to move "Context/Application-dependent code" out of Activities and Fragments without requiring a risky refactor. Accessing Application in the view model will be necessary in that scenario.


  1. If there is any reason to use AndroidViewModel, can one not derive from ViewModel + use dagger2 for the application inject?

If you're not injecting anything else, then at best it's a convenient way to get an Application reference without having to type cast or use any DI at all.

If you're injecting other members, be it with a DI framework or ViewModelFactory, it's a matter of preference.

If you're injecting a ViewModel directly into your Activity/Fragment, you're losing the benefits the platform is providing you with. You'll have to manually scope the lifecycle of your VM and manually clear your VM for your UI's lifecycle unless you also mess around with ViewModelStores or whatever other components are involved in retention. At that point, it's a view model by name only.

Android different ways to create viewModel object which one to use when?

In case anyone looking for in depth answer, please check this, here we have the following way to create or get the viewModel object:

  1. val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)

  2. myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)

  3. val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)

  4. val myViewModel4: MyViewModel by viewModels()

  5. val myViewModel5 by viewModels<MyViewModel>()

All do the same thing, the only two key differences is:

  1. The viewModel initialisation with lazy loading and without lazy loading.
  2. The viewModel with multiple parameter and no parameters.

Lets see this wrt the lazy loading and without lazy loading, the first three are without the delegate by that means there is no lazy loading of that object, so it's the developer
responsibility to create the viewModel object only when activity is created or the fragment is attached to the activity, that means the first three approach(1, 2, 3) can't be
used at global scope, if used at global scope the variable must be
a var with lateint or null initialisation, and the
initialisation(approach 1, 2, 3) must happen in the onCreate or
onViewCreated(in case of fragment).

Therefor the best way to create the viewModel object is using the delegate by(4, 5), both are same with a bit different syntax, I choose 4 because of it's simplicity and readability.

val myViewModel4: MyViewModel by viewModels()

The by delegate gives the flexibility to lazy load the instance and you can define the viewModel at global scope and get ride off the boilerplate code, if you try to initialise the viewModel at global scope without the delegate the app will crash since the viewModel will try to initialise before the activity is created(it will not lazy load the viewModel instance).

Now let's see how to lazy load with multiple parameters, the 6th approach not mention in the question.

If you have multiple parameters in your view model and not using any dependency injection, you can use a ViewModelFactory implementation and then lazy load it:

val myViewModelWithParm: MyViewModel by viewModels { MyViewModelFactory(application, "param1", "param2") }

ViewModelFactory implementation:

    class MyViewModelFactory(val application: Application, val param1: String, val param2: String) :
ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MyViewModel(application, param1, param2) as T
}
}

Till this point we are clear on the delegate initialisation(4, 5), and how it is different with(1, 2, 3) now let's see the difference on the top 3 approach(1, 2, 3).

Let's first check 1 and 2.

  1. val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
  2. myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)

The key difference in them is one uses ViewModelProvider.NewInstanceFactory and other uses ViewModelProvider.AndroidViewModelFactory, so I checked the source code of both the classes and found that ViewModelProvider.AndroidViewModelFactory is actually the implementation of ViewModelProvider.NewInstanceFactory which override the create function that means both are doing the same stuff, preferable both approach should be chosen if we want multiple parameters however for that we have to override ViewModelProvider.NewInstanceFactory to create our own factory like it's done here

Now comes the third one:

val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)

This is the simple form of 1 and 2 when we don't have multiple parameters in our ViewModel and don't want to lazy load the object.

Note: I highly recommend the approach 4 or 5(both are same with different syntax), since this is the most suitable and optimal to write, if you don't have multiple arguments, in case you have multiple arguments you can use the approach 6 mentioned in the answer by implementing ViewModelProvider.Factory.



Related Topics



Leave a reply



Submit