The documentation states the following:
If the ViewModel needs the Application context, for example to find a system service, it can extend the AndroidViewModel class and have a constructor that receives the Application in the constructor, since Application class extends Context.
Code example:
class MainViewModel(application: Application) : AndroidViewModel(application) {
...
}
Two questions:
How does the AndroidViewModel helps me if I need to pass Application to ViewModel's ctor anyway?
And again, if I need to pass Application, why do I need AndroidViewModel? I can just use ViewModel and pass it Application.
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.
You can write your custom ViewModel without extending AndroidViewModel and it will be functionally identical.
Only difference is default ViewModelFactory checks if ViewModel is an instance of AndroidViewModel and invokes one-arg constructor passing down Application context automatically.
Related
I researched a lot but I didn't understand the basic difference between the following topics. Please, tell me what is the basic difference between them and when to use them. And if possible please provide article links other than the Android developers guide. Thanks a lot!
ViewModel
AndroidViewModel
ViewModelProvider.Factory
ViewModelProvider.NewInstanceFactory
ViewModelProvider.AndroidViewModelFactory
It's easier to start by explaining the factories.
ViewModelProvider.Factory is necessary because the framework needs a way to be able to create instances of your ViewModel on your behalf, because it has to do this when returning from process death. You don't create instances directly yourself except inside the Factory.
The framework automatically provides some default factories that are capable of creating instances of your ViewModel if your ViewModel constructor's arguments are one of the following:
constructor() Empty constructor (no arguments)
constructor(savedStateHandle: SavedStateHandle)
constructor(application: Application)
constructor(application: Application, savedStateHandle: SavedStateHandle)
So if your ViewModel constructor is like one of the above, you don't have to create your own ViewModelProvider.Factory. In your Fragment or Activity, you can simply use private val viewModel: MyViewModel by viewModels() to create it using the default factories.
You don't need to touch or even think about NewInstanceFactory or AndroidViewModelFactory. They are subtypes of Factory that the framework uses as the default implementations that can construct the above types of ViewModels.
AndroidViewModel is a ViewModel with an Application property. If your ViewModel constructor is like one of the last two in the list above and you want to avoid creating your own factory, you must subclass AndroidViewModel instead of ViewModel. The default factories for some reason will only handle those last two if your factory is an instance of AndroidViewModel. (Seems like an unnecessary and pointless restriction to me, but maybe I'm missing something.)
While using Room Database i found that classes like Repository and ViewModel used Application Context as arguments in their Constructors.
I Just want to know the reason,why this is done?
And is it a Compulsion to use the application context?
public WordViewModel (Application application) {
super(application);
mRepository = new WordRepository(application);
mAllWords = mRepository.getAllWords();
}
WordRepository(Application application) {
WordRoomDatabase db = WordRoomDatabase.getDatabase(application);
mWordDao = db.wordDao();
mAllWords = mWordDao.getAllWords();
}
Curious to Know the reason behind the stuff
Why can't we use a Activity Context?
Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.
ViewModel objects are designed to outlive specific instantiations of views or LifecycleOwners. This design also means you can write tests to cover a ViewModel more easily as it doesn't know about view and Lifecycle objects.
Why can we use a Application Context?
If the ViewModel needs the Application context, for example to find a system service, it can extend the AndroidViewModel class and have a constructor that receives the Application in the constructor, since Application class extends Context.
See ViewModel
let me give you a lazy answer to this question. Application context lifecycle is tied to the lifecycle of the application whereas activity context is tied to the lifecycle of that activity. Make sure to use the right context to prevent memory leaks . Hope this helps
I am extending AndroidViewModel to get an application context in my ViewModel but Now I also want to pass some parameters to my ViewModel.
After some google search, I came to know that I can use ViewModelProvider.Factory to get Parametrized constructor of my MyViewModel but how to get an application context.
Thanks in advance.
You would need an Application in ViewModel.Factory to instantiate an AndroidViewModel.
Ways to achieve this
if you are instantiating the ViewModel in your Activity/Fragment then do getApplicationContext() and cast it as Application. If in fragment you can get the hosting Activity and get Application from it.
// Kotlin code
viewModel = ViewModelProviders.of(this,
ViewModel.Factory(activity?.application!!, param1, param2)) // from an fragment onViewCreated()
if your app has an Application class expose an method to get an application instance.
// JAVA code
public static Application getApp() {
return YourApplication.instance; // instance will be an static field in Application class
}
From your activity you can use:
Kotlin:
applicationContext
Java:
getApplication().getApplicationContext()
I'm studying google's architecture components to implement ViewModel and LiveData to my app, and the official documentation says that:
Note: Since the ViewModel outlives specific activity and fragment instantiations, it should never reference a View, or any class that may hold a reference to the activity context. If the ViewModel needs the Application context (for example, to find a system service), it can extend the AndroidViewModel class and have a constructor that receives the Application in the constructor (since Application class extends Context)
Following that, I ended up with a code like that:
public class ViewModelTest extends AndroidViewModel {
public ViewModelTest(Application application) {
super(application);
}
public void test(){
Prefs.getCurrentCode(getApplication());
}
And should I instantiante it normally on the activity?
val viewModel2 = ViewModelProviders.of(this).get(ViewModelTest::class.java)
viewModel2.test()
Isn't it bad? To use this application variable when need to access SharedPreferences or anything that need a context?
And if it is, should I avoid using it on the ViewModel and use it only on the view? Specially if I want to update a UI component with a value that needs a context. I kinda don't know how to approach this issue, and I'm open for any suggestions.
Thanks in advance
AndroidViewModel class is provided as part of the android.arch.lifecycle package which is part of Android's architecture components. It itself calls for the Application Context passed into the constructor. The Application Context lives across the Activity lifecycle.
An Application context in a ViewModel is okay because the Application context is tied to the whole Application lifecycle as opposed to an Activity context, which is tied to the Activity lifecycle.
ViewModel documentation specifically is referring to not use the Activity Context, but the Application Context if fine.
With the introduction of the Android Architecture Components library, several new classes were introduced, including AndroidViewModel and ViewModel. However, I'm having trouble figuring out the difference between these two classes. The documentation succinctly describes AndroidViewModel as follows:
Application context aware ViewModel
I appreciate the brevity, but what exactly does this imply? When should we choose to use AndroidViewModel over ViewModel and vice-versa?
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.
Finally I got something a simpler explanation, a bit......
...The AndroidViewModel class is a subclass of ViewModel and similar to them, they are designed to store and manage UI-related data are responsible to prepare & provide data for UI and automatically allow data to survive configuration change.
The only difference with AndroidViewModel is it comes with the application context, which is helpful if you require context to get a system service or have a similar requirement. the bold text makes it clearer to sense it.
AndroidViewModel is subclass of ViewModel. The Difference between them is we can pass Application Context which can be used whenever Application Context is required for example to instantiate Database in Repository.
AndroidViewModel is a Application context aware ViewModel.
AndroidViewModel:
public class PriceViewModel extends AndroidViewModel {
private PriceRepository priceRepository;
public PriceViewModel(#NonNull Application application) {
super(application);
priceRepository= new PriceRepository(application);
allPrices = priceRepository.getAllPrices();
}
ViewModel:
public class PriceViewModel extends ViewModel {
public PriceViewModel() {
super();
}
You Should use AndroidViewModel only when you require Application
Context.
You should never store a reference of activity or a view that references a activity in the ViewModel.Because ViewModel is designed to outlive a activity and it will cause Memory Leak.
Apart from the difference that AndroidViewModel gives you an application context whereas ViewModel does not. The important thing that you must understand is that Google itself recommends using ViewModel and not AndroidViewModel.
So, don't use AndroidViewModel unless it is really necessary.
See this: GOOGLE DOC