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()
Related
I have a ViewModelProvider.Factory instance that is responsible for instantiating ViewModels and injecting repositories into the ViewModels.
This works well for Fragments as I simply supply my custom Fragment factory with the ViewModel factory:
this.supportFragmentManager.fragmentFactory = MyFragmentFactory(myViewModelFactory)
The fragment factory injects the ViewModel factory into the Fragments when instantiating them. The Fragments can then access the ViewModels through:
mapViewModel = ViewModelProvider(this, myViewModelFactory).get(MyViewModel::class.java)
However, I want to launch a new Activity that will also require access to the same ViewModel factory.
Can I share my ViewModelProvider.Factory instance across Activities without using a global variable?
Use the Common class concept. Make a common class and a public static variable of your required Datatype and store values there and when you need to access just use Common.YOUR_VARIABLE_NAME;
Public class Common{
public static REQUIRED_DATATYPE variableName;
}
store the value which you need to access in another activity as
Common.variableName = YOUR_VALUE;
and when you need to use just type Common.variableName
Feel free to ask if something is unclear.
Sorry for the stupid question but upon reading about ViewModel i came across
randomViewModel = ViewModelProviders.of(this).get(RandomViewModel::class.java)
I just want to know what the of() is in general. Is it just a function used by the providers? Or is it a special operator?
Thanks
#Deprecated
#NonNull
#MainThread
public static ViewModelProvider of(#NonNull Fragment fragment) {
return new ViewModelProvider(fragment);
}
As we can see by viewing the source code of ViewModelProviders, of() is basically an extension function of ViewModelProvider that returns a new NonNull ViewModelProvider object with the parameter fragment/activity and locks it on the MainThread. Basically it's a fancy way of writing ViewModelProvider(fragment) with extra steps.
But be aware that of() is deprecated, you now initialise a ViewModel like this:
ViewModelProvider(requireActivity(),ViewModelFactory(Database.getDatabase(requireActivity()))).get(ViewModelClass::class.java)
ViewModelProviders.of(this).get(RandomViewModel::class.java)
ViewModelProviders.of(this)
It is a static function that takes current context to retain the ViewModel scope. In this case Current activity is gonna be the context for which ViewModel scope will be retained.
.get(ViewModel::class)
It does two things
If the ViewModel is available it will return the ViewModel instance.
Otherwise, it will create and return the new instance.
The of() method here is a method inside the ViewModelProviders class which just creates a ViewModelProvider object, which retains ViewModels while the scope you have given eg Activity, Fragment is alive.
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.
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'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.