I have recently been integrating Dagger into a project that uses ContentProviders. I create a single ObjectGraph instance in my custom Application object, and basically in each managed component:
Activity,
Fragment,
Service
... Then, I call getApplication(), downcast to my custom Application object, and force the injection through some custom implementation in my Application class. This seems to be the prescribed method of performing injection based on the samples I've seen posted by the guys at Square.
This pattern doesn't hold for ContentProvider instances though as their lifecycle isn't as predictably tied to the lifecycle of the Application object, ie ContentProviders can be, and as I'm observing frequently are, created before the Application object is created (for reasons I have yet to comprehend).
so... does anyone have a nice way of injecting ContentProviders using Dagger? I've so far made it by having an isInjected() call at the beginning of each of my ContentProvider's interface methods (insert, query, update, delete)... basically a hacky form of lazy initialization. But this seems far from ideal. Is there a more prescribed approach to injecting ContentProviders?
The Application subclass is just a convention since it's usually the first object created. Our apps do not have content providers which is why we use them. There's nothing that says you can't put it somewhere else.
You can just use the traditional singleton pattern for instantiating and holding a reference to the ObjectGraph.
public final class Dagger {
static ObjectGraph og;
static ObjectGraph og() {
if (og == null) {
og = ObjectGraph.create(..);
}
return og;
}
}
The first person to access will initialize the instance which will be used for the lifetime of the process.
If your content provider is in a different process than your main application this solution will still work. Or you could simply create the graph when your content provider is created since it will be the only consumer. Normal multi-process rules still apply, of course, so no instances will be shared with the other processes.
Related
What is the use of this private constructor and why we instantiate it's object under the class.
DatabaseHelper._privateConstructor();
static final DatabaseHelper intance =DatabaseHelper._privateConstructor();
In general, we'll use a private constructor when we don't want things to be instantiated more than once. This lets us implement the singleton pattern:
https://www.geeksforgeeks.org/singleton-design-pattern/
In this case, we don't want multiple instance of the database. So, it'll instantiate the database if it hasn't already been instantiated, or it'll return the existing instance of the database if it has been instantiated previously.
It is a design pattern called the singleton pattern.
It's main purpose is to ensure that only one instance of that class ever exists in the application.
To ensure this purpose, the pattern implements techniques that have serious disadvantages. People are overusing it, sometimes using it as a justification as to why they have those disadvantages in their program that would otherwise be considered bad design. It has become an anti-pattern. See Why is Singleton considered an anti-pattern?.
In addition to given answers, it is Eager singleton, therefore once the class is initialized, the instance is also initialized, even the instance is not used. However still it has been instantiated only once.
See also Singleton lazy vs eager instantiation
As the other answers state, it's the singleton pattern. Here's a link that explains it more.
A long time i have been struggling with dagger components.
At first i made Injectors class for each custom scoped component which contained static field either with WeakReference<Component> or just a Component, so that i always had an access to this component through static method.
But i think thats a pretty bad approach because WeakReference could be cleared so you will not get the same Component, as well as you can just forget to clear Component in static field.
I designed another approach when i have ComponentsHolder interface which is implemented by App and contains some methods to add, delete, and check if component exists in a HashMap<String, Component> inside the same App class.
So this approach combined with kotlin extensions for Context gave me a great opportunity to inject thing anywhere i have Context like this:
context.injector(Component::class) {
inject(this#ObjectWhereToInject)
}
So i mind maybe i doing something wrong? Or is there a better approach to store and retrieve dagger components?
So, what I am trying to accomplish is to ensure that I have only one instance per scope in Dagger2.
Default Singleton scope already works that way. No matter on how many places you inject same object, let's call it GlobalInstance, method GlobalInstance provideGlobalInstance() that constructs it will be called once and only once.
On the other side, if I define custom scope, for example #SessionScope and inside some SessionModule I make method User provideUser(), that method (and, consequentially, new User() constructor) will be called as many times as I am injecting User. No matter if I use the same module instance every time, User provideUser() is being called for every #Inject User mUser I have in my code, resulting with multiple instances, instead of one scope-limited "singleton".
Is there some clear way to achieve it, using regular Dagger api. One way to do it is to have lazy getters inside the module class, but it is not very clean way to do it.
Please note that #Singleton scope is functionally equivalent to any other custom scope you define.
It means that you could have two flavors of #Provides methods in SessionModule:
#Provides #SessionsScope - provides "session singletons" (more on this later)
#Provides - provides new object on each injection
Please note that the term "singleton" have some ambiguity when we talk about Dagger, therefore I prefere to use term "scoped objects". When scoped object injected with Dagger for the first time, the component caches its instance and returns it on each subsequent injections PERFORMED BY THE SAME COMPONENT.
For more information you can read this post: Android Dagger 2 Scopes Demistified
I have an Android Activity that I'm using Dagger2 to inject a Presenter into. I'd like my Presenter to be capable of holding state even if a configuration change occurs.
For instance, I'm going to use the Presenter to kick off a network call and if the user rotates the device while the network call is in-flight I'd like to be able to receive the response after the device finishes its rotation and not have to restart the call.
I'm getting tripped up because if I scope the instance of Presenter to the Activity's life, then isn't there a chance that the Presenter would be garbage collected when the Activity goes through onDestroy() during a configuration change? My other thought was to use a scope that is valid during the life of the application. However, if I do that how do I ensure that my Presenter can be garbage collected once the Activity has been destroyed for good (not due to a config. change, but something like the back button being pressed)?
Is there a way to ensure that my Presenter will survive an Activity's configuration change and also not be leaked for the life of the Application?
I would strongly advice against trying to implement this approach.
You're effectively trying to use DI framework in order to support Activity specific life-cycle flow, although DI frameworks are not intended to be used like this.
I recently answered another similar question in which OP tried to share state in View-Model between different Activities. Although use cases are not identical, the general pattern is the same - attempt to delegate flow control responsibilities to DI framework, which is not a good idea.
The best approach in your case (IMHO) would be to store the current state before rotation, re-instantiate the presenter upon rotation, and then restore its state.
How you store the state during rotation depends on what exactly you're trying to preserve:
If you need to preserve UI related state (selections, texts, position of elements, etc.) then you can use the usual onSaveInstanceState() and onRestoreInstanceState() callbacks
If you need to preserve some business related state (ongoing network requests, data, data modifications, etc.) then encapsulate this logic in a business class (e.g. SomeBusinessUseCaseManager) and inject this class from Application wide component with a scope.
You can find a detailed review of Dagger's scopes here.
More information about DI in Android can be found here.
According to this article about Custom Scopes:
http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/
In short - scopes give us “local singletons” which live as long as scope itself.
Just to be clear - there are no #ActivityScope or #ApplicationScope annotations provided by default in Dagger 2. It’s just most common usage of custom scopes. Only #Singleton scope is available by default (provided by Java itself), and the point is using a scope is not enough(!) and you have to take care of component that contains that scope. This mean keeping a reference to it inside Application class and reuse it when Activity changes.
public class GithubClientApplication extends Application {
private AppComponent appComponent;
private UserComponent userComponent;
//...
public UserComponent createUserComponent(User user) {
userComponent = appComponent.plus(new UserModule(user));
return userComponent;
}
public void releaseUserComponent() {
userComponent = null;
}
//...
}
You can take a look at this sample project:
http://github.com/mmirhoseini/marvel
and this article:
https://hackernoon.com/yet-another-mvp-article-part-1-lets-get-to-know-the-project-d3fd553b3e21
to get more familiar with MVP and learn how dagger scope works.
For example, let's say my Rest adapter created with Retrofit lives inside Application class.
I would love to get it inside the Activity, so I write the following code:
public class MainActivity extends Activity {
#Inject MyRestAdapter mRestAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((GlobalApplication) getApplication()).getComponent().inject(this);
}
}
Granted, it will make the job done. But...
How is this different from calling getApplication(), and then explicitly yank the MyRestAdapter to MainActivity? Yes, Dagger 2 will simplify the setup by automatically getting everything to the Activity, but you still need to explicitly tell from where you need these dependencies, and that, if I understand correctly, defeats the whole purpose of DI. Am I right to say that Dagger 2 is "semi-automated service locator", or it's just the tutorials that misled me, and there is correct way to inject dependencies with Dagger 2 into the View or Activity from Application?
I've been experimenting with Dagger and it definitely seems to blur the lines between service locator and dependency injection. This is at least true when used with Android activities. With the current version of Dagger, it is possible to write AndroidInjection.inject(this) in an activity's onCreate method. That's basically like saying "find all the services I need and inject them into me." So Dagger is a combination of a some central/global service locator that knows where to get the services and an injector that knows where (i.e. which instance variables) to put those services in the activity. It seems that Android activities force reliance on some kind of singleton/global object.
There is no 1 "purpose of DI" but definitely one of them is to separate the configuration from what actually requests the configured objects. The idea is that your higher-level objects, such as Activitys in Android, can request all of the objects it needs without worrying about where they come from, how they are constructed, and any semantics about their relationships. Similar to how an Activity doesn't deal with drawing text to the screen (and instead delegates that to a TextView[0]), DI helps keep your objects from knowing too much that is not relevant to the actual logic they need to perform.
Inherent in the "semi-automated service locator" you describe is static analysis and error handling. As applications become larger, it becomes even harder to get manual-DI correct. Dagger helps make your code less error-prone (and less tedious to maintain).
Consider the case where you have an internal version of your app for employees, where you log lots of information about how they use the app to make sure you can identify any issues. In your actual product, however, you don't want to track personally identifiable information like that when it's not necessary. Now, your MainActivity needs an AnalyticsLogger - which one should it get? The more cases you have, the easier it is for Dagger to help piece things together than for you to do it yourself.
[0] which delegates to a Paint object