I am using a library that needs the Application class (not the application context) that I am using to work
its builder is something like Library.Builder.setApplication(app).setParameters(...).build()
is there a way to use the currently created Application in Hilt? #ApplicationContext obviously does not work
I'm not 100% sure, but maybe you can cast Application Context to Application class. I had similar problem when I needed Activity instance in provides method. I cast Activity Context from Hilt annotations and it works.
Simply inject the Application class:
class MyClass #Inject constructor(
private val application: Application,
)
Related
In regards to #ApplicationContext and #ActivityContext in Hilt, I understand that they help to resolve ambiguity when a Context is being requested… but why not just request Application or Activity directly?
It depends on what you need, when you just need a context(call methods in the context class), then inject the context. If you really need an Activity, you can inject it to your class.
But when you inject some class, it means your class depends on it and they are coupled. That's a bad practise in software design. When you inject an activity into your class, that means your class only works with that activity. If you inject an context, your class can work with any subclasses that implements the Context class
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.
So I'm having to write unit tests and I need to test my ViewModels.
I have a base ViewModel and that BaseViewModel extends AndroidViewModel. The reason I extend AndroidViewModel is so that I can use the context for Dagger.
My BaseViewModel.
public class BaseViewModel extends AndroidViewModel {
protected #Inject SharedPreferencesHelper sharedPreferencesHelper;
public BaseViewModel(#NonNull Application application) {
super(application);
//Only inject sharedPreferences since it is used in almost all of the VMs.
((CommissioningApplication) getApplication()).getAppComponent().inject(this);
}
}
Essentially I'm having issues creating an instance of my ViewModel in my unit tests. I have tried many things and have been unsuccessful.
I have considered extending ViewModel instead of AndroidViewModel and creating a Factory that will pass the application context to my ViewModels. But in the end I will run towards the same issue whenever I try to create an instance of my ViewModel.
Does anyone have an example that I could follow on how to test this? Or would have I have to do Instrumented testing instead of Unit testing?
I'm very new to testing so maybe I'm not doing things properly, any help would be great.
Thanks
As stated here:
Mockito.mock(Application::class.java)
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