Is it possible to scope this and provide a release method in the module or elsewhere to prevent memory leaks. Ex. I need to close a database connection in onDestroy() but it would be nice if this could be handled by the module itself.
Consider the following example* code.
*Read the error prone code at your own risk
Module
#dagger.Module
#lombok.NoArgsConstructor
public class PersistenceModule {
#Provides
#Singleton
DatabaseProvider providesDatabaseHelper(Context context) {
return new DatabaseProvider(context);
}
}
Activity
public class SomeActivity extends Activity{
#javax.inject.Inject DatabaseProvider provider;
//..onCreate omitted where injection happens.
#Override
protected void onDestroy() {
//Close database and cleanup.
provider.release();
provider = null;
super.onDestroy();
}
}
Your sample seems error-prone, as you are scoping your DatabaseProvider with a #Singleton scope, but use and clean it up in an activity.
A Module just helps creating objects—especially if there is no injectable constructor or it needs further initialization—and is not aware of further lifecycle events. It supplies its objects to a Component, which just holds and creates the object graph needed to inject your classes. In the end both are just plain old java objects and a scope on a component is nothing more than syntactic sugar helping with compile time validation.
In any case, you should handle your cleanup at the same scope that you provide your dependency. #Singleton scope should therefore be cleaned up in the application object that is also holding the application component. If you clean up a singleton scoped object in an activity, the next activity accessing it would be accessing an object in a closed state.
If every activity should have its own accessor and clean it up after being used, then you should switch to some activity based scope. Additional scopes are just annotations that you can create yourself.
The actual cleanup
All this said, I would not include "clean up" logic in my modules, because most people would not expect to find it there.
#Module
Annotates a class that contributes to the object graph.
Dagger is a dependency injection framework that provides dependencies for easier usage of interfaces and looser coupling of your classes. It is to reduce boiler plate code of object creation and what you do with the actual objects once you have them should not belong to the same code base creating them.
While it would still be possible to keep references to you modules, or make them implement some interface (still pojos!) and call them to clean up themselves in onDestroy it would probably lead to more confusion than just doing the cleanup where others would expect it.
Related
Please don't mark this duplicate, I've read all the other answers about this issue. I'm not asking what the issue means, I'm asking why this particular code produces this error.
I'm trying to make an Activity component/injector that uses SessionComponent as its parent:
AppComponent:
#Singleton
#Component(modules = [AppModule::class, AndroidSupportInjectionModule::class])
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun application(ltiApp: LTIApp): Builder
fun build(): AppComponent
}
SessionComponent:
#SessionScope
#Component(
dependencies = [AppComponent::class],
modules = [SessionModule::class, CommentaryModule::class, EducationCenterModule::class])
interface SessionComponent {
EducationCenterModule
#dagger.Module
abstract class EducationCenterModule {
#EducationScope
#ContributesAndroidInjector()
abstract fun educationCenterActivity(): EducationCenterActivity
}
How come I get an error for injector factory even though I have #ContributesAndroidInjector inside a Module?
Caused by: java.lang.IllegalArgumentException: No injector factory
bound for
Class
If possible, move your #ContributesAndroidInjector into your AppModule, which will likely involve some refactoring between AppComponent and SessionComponent.
dagger.android injects Activity instances by calling getApplication() on the Activity, casting that to a HasActivityInjector, and calling activityInjector().inject(activity) on it (code). In turn, apps that use DaggerApplication (or the code on the dagger.android how-to page) will inject a DispatchingAndroidInjector<Activity>, which injects a Map<Class, AndroidInjector.Builder> that is built using multibindings. Though it's possible to inject into this map directly, you may also use #ContributesAndroidInjector (as you have done here) as a shortcut that produces the multibinding and subcomponent.
Though you have #ContributesAndroidInjector bound inside a #Module, you have two top-level components: AppComponent and SessionComponent. dagger.android is not prepared for this: Your Application likely uses AppComponent for its injection, and because you haven't installed EducationCenterModule into AppComponent, the multibound map will not contain the binding that your #ContributesAndroidInjector method installs.
This probably requires some refactoring, but for important reasons: Through intents, back stacks, and activity management, Android reserves the right to recreate your Activity instance whenever it wants to. Though your Application subclass likely guarantees that an AppComponent will exist by then (by creating and storing that component within onCreate), there is no such guarantee that your SessionComponent will exist, nor any established way for an Android-created Activity instance to find the SessionComponent that it can use.
The most common way to solve this problem is to separate the Android lifecycle from your business logic, such that dagger.android manages your Android components on their own lifecycle, and those Android components create/destroy SessionComponent and other business logic classes as needed. This may also be important if you ever require Service, ContentProvider, or BroadcastReceiver classes, as those will definitely only have access to the application, and may restore or create sessions of their own. Finally, this also means that a Session will necessarily last longer than an Activity instance, which might mean that your Session will not be garbage collected until Android destroys your Activity, and may also mean that you have multiple concurrent SessionComponent instances.
Edit/elaboration: First and foremost you'll need to decide whether sessions outlive Activities, Activities outlive Sessions, or neither. I bet it's "neither", which is fine: at that point I'd write an injectable #Singleton SessionManager that goes inside AppComponent and manages the creation, recreation, and fetching of SessionComponent. I'd then try to divide it so most of the business logic is on the SessionComponent side, and by calling sessionManager.get().getBusinessObject() you can access it from SessionComponent. This also works well to keep you honest, since the business logic side might be easy to unit test using Robolectric or Java, while the Android side might require instrumentation tests in an emulator. And, of course, you can use #Provides methods in your AppComponent modules to pull out your SessionComponent, BusinessObject, or any other relevant instance out of the SessionManager side.
However, if you are 100% sure that you want SessionComponent to be the container for your Activity, and that you don't mind managing the session creation and deletion in your Application subclass. If that's the case, then rather than using DaggerApplication, you can write your Application subclass to implement HasActivityInjector (etc), and delegate the activityInjector() method to a class on a SessionComponent instance that you create. This means that AppComponent would no longer include AndroidSupportInjectionModule, because you no longer inject DispatchingAndroidInjector or its Map. However, this is an unusual structure with implications for your application, so you should consider your component structure carefully before proceeding and document it heavily if you choose the non-standard route.
My Goal :
To understand how scope works and how to Implement a UserScope that I can use over multiple Activities and reset/create a new one as required.
Methods I am using :
This Blog: http://frogermcs.github.io/building-userscope-with-dagger2/
It apparently explains the same thing that i am trying to achieve here.
Official Docs
http://frogermcs.github.io/building-userscope-with-dagger2/
Quick brief on Blog
Obviously, There is UserModule and UserComponent. Author has wrapped the creation of UserComponent under UserManager which has ApplicationScope. So UserManager is available at time of log in. when login is successful UserComponent is initialized via UserManager. Simple logic.
Now this already initialized #UserScope is used in couple of Activities, as you can see in the picture.
What I am struggling to understand
Take a look at UserComponent.
public interface UserComponent {
#Subcomponent.Builder
interface Builder {
Builder sessionModule(UserModule userModule);
UserComponent build();
}
UserDetailsActivityComponent plus(UserDetailsActivityComponent.UserDetailsActivityModule module);
RepositoriesListActivityComponent plus(RepositoriesListActivityComponent.RepositoriesListActivityModule module);
LogoutManager logoutManager();
}
Specifically UserDetailsActivityComponent and RepositoriesListActivityComponent are created through UserComponent. Like this,
#Override
protected void onUserComponentSetup(UserComponent userComponent) {
userComponent.plus(new UserDetailsActivityComponent.UserDetailsActivityModule(this)).inject(this);
}
So they first get pre-created in UserComponent through UserManager and then it calls onUserComponentSetup which then creates the appropriate Component and injects the current Activity.
I fail to comprehend with this pattern mentioned above, as I have read in the docs that we use plus(InjectionToBeDoneOn i) when we need the injection on a particular instance of InjectionToBeDoneOn. But why inject this Activity via this Component? What does this accomplish? Wouldn't it make sense to do this the conventional way in onCreate() of the activity with DaggerXYZComponent().Builder().Build().inject(activity)?
Also, I am missing decent material of how UserScope is implemented in Android which has life span from log-in to log-out but not bigger than the #Singleton scope.
we use plus(InjectionToBeDoneOn i) when we need the injection on particular instance of InjectionToBeDoneOn
Not quite. A component has basically 3 kinds of methods
SomeDependency provideDependency() which just creates / provides some dependency to subcomponents, or for manual retrieval (basically a getter)
void inject(MyAndroidFrameworkClass object) that injects an object with its dependencies
SomeSubComponent plus(SubComponentModule module) that creates a subcomponent, adding additional modules
You're mixing up 2. and 3. here.
// user scoped component
userComponent
// create a subcomponent (UserDetailsActivityComponent)
.plus(new UserDetailsActivityComponent.UserDetailsActivityModule(this))
// use the UserDetailsActivityComponent that was just created and inject with it
.inject(this);
UserDetailsActivityComponent is a subcomponent of UserComponent, which is why the userComponent gets extended .plus(somemodule) to create a subcomponent. If your submcomponent does not need additional modules you can also just use .plus() because to Dagger the important thing is the return type or signature in general.
If it returns another component, then it creates a SubComponent.
If it hast one parameter and returns void or the parameters type, then it is an inject method
If it has no parameters and returns some type is is a provides method (1.) to expose some dependency
but why inject this Activity via this Component? What does this accomplish?
If you were to create UserDetailsActivityComponent from scratch, it would only see and know about what it can provide itself. If you have some #Singleton somewhere it could not access any of it, because it is not part of the object graph.
A subcomponent extends another component, adding to the object graph. If you have a #Singleton A and your UserComponentn needs A to provide B, with a subcomponent this will work, without it you will get a cannot be provided error.
Dagger is no magic. It really just builds up a directed graph and checks whether everything is fine. It will complain if some dependencies have cyclic dependencies on one another or if some part of the graph doesn't have access to dependencies it need.
Your UserComponent holds your userdata. For simplicity lets say it holds the UserName. Now UserDetailsActivity might want to display UserName, but it needs some way to get it.
By using the #Singleton AppComponent as a parent you'd have access to some Apis, but not the user scoped ones. You could move the user scoped objects into the #Singleton AppComponent, but then you'd either have to recreate the AppComponent every time the user changes (which kind of defeats the purpose of declaring it #Singleton, or you'd have to find some other means to update / change the user.
If you want to do it the Dagger way, you create a UserComponent that adds the User to the graph. That way subcomponents can access it and do their user things.
When the user changes you have to make sure to destroy any activities / fragments that used the UserComponent, and you just recreate everything—with a new user.
wont it make sense to do in conventional way in OnCreate() of the activity with DaggerXYZComponent().Builder().Build().inject(activity)
You can do that of course. The author just put the calls to app.getAppcomponent().getUserManager().getUserComponent() or something like this into their BaseActivity and BaseUserActivity so that you wouldn't have to repeat the same lines of code every time. This method will basically still be called in onCreate, it just enables you to use the components directly, without fetching them every single time.
You can obviously remove those template methods and inline everything in onCreate, leading to duplicated code, making maintenance harder in the long run.
i am missing decent material of how UserScope is implemented in android which has life span from log-in to log-out but not bigger than #SingleTon scope.
Android doesn't help and it's your job to clean up after yourself. If the user changes you purge everything the UserComponent and its SubComponents touched, and recreate it with the new user.
You will have to store the UserComponent with the current user either in the Application class, some "real" singleton, or some "Manager" in the application component with a #Singleton scope. Every approach has their own benefits I guess.
Scopes just point out to Dagger that one object should exist within a Scope only once. It doesn't matter what you name it, or how many objects are in the Scope. Dagger only needs them to ensure that there are no dependency cycles.
The project I'm working on has a number of utility classes that require activity context.
I don't want to have to declare a new #Provides method for each activity that uses the dependency. i.e. I don't want this:
#Provides
static Navigator providesNavigator(ActivityOne activity) {
returns new Navigator(activity);
}
// ...and in another module
#Provides
static Navigator providesNavigator(ActivityTwo activity) {
returns new Navigator(activity);
}
So instead I declare these utilities in a single ActivityUtilitiesModule and pass our BaseActivity which all other activities extend. Now i don't have to declare my Navigator dependency x number of times.
#Provides
static Navigator(BaseActivity activity) {
return new Navigator(activity);
}
However, Dagger does not know how to satisfy the dependency for BaseActivity. This means for every Activity i need to create a provides method that will satisfy the BaseActivity dependency with the specific Activity being used. e.g.:
#Provides
static BaseActivity providesBaseActivity(ActivityOne activity) {
return activity;
}
This is better - I only need to repeat this one provider per activity, rather than repeating a provider for every utility class per activity, but it still feels like an unwelcome additional step in Dagger set up, and another thing that makes the code harder to understand.
Is there a pattern which allows me to avoid having to supply this BaseActivity provider per activity?
Please use Constructor Injection. Having provide* methods that only call the constructor are only noise and code to maintain. Add #Inject to the class constructor and possible scopes onto the class.
#SomePossibleScope
class Navigator {
#Inject
Navigator(Activity activity) { }
}
If you do this, you probably don't need your ActivityUtilitiesModule at all.
If your class depends on an Activity or BaseActivity then you need to provide it. And yes, you will have to tell Dagger about it in some way.
If you were to use an abstract class or interface you should make use of #Binds instead.
#Binds BaseActivity bindsBaseActivity(ActivityOne activity);
Compared to #Provides Dagger might optimize this code further, reducing the number of method calls and object creations, as well as a few less lines of code.
I don't know why your Utils depend on the Activity, but if they would only need a Context then you could also just provide the application context to them without a need to bind or provide your actual Activity.
I personally just bind the current Activity to the types it implements using the syntax above. And if you're using Constructor Injection properly that's more often than not the only lines of code that you'll find in my modules, making them very readable.
Following code creates & shares same object of injected dependencies(ViewsApiEnd ) with different activities rather than creating different per activity.
#ActivityScope
#Component(dependencies = HttpComponent.class, modules = ViewsApiModule.class)
public interface ViewsApiComponent {
void inject(MainActivity activity);
void inject(SecondActivity activity2);
}
module:
#Module
public class ViewsApiModule {
#Provides
#ActivityScope
public ViewsApiEnd providesGitHubInterface(Retrofit retrofit) {
return retrofit.create(ViewsApiEnd.class);
}
}
Scope:
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ActivityScope{
}
Full Source: Github(If anyone could fork & correct scope issue it'll be helpful. Also checke void logInstances() for verifying object creation )
How should I declare ViewsApiComponent if I want dagger2 to create different objects of injected deps( ViewsApiEnd) for different activities(MainActivity , SecondActivity )?
I'm assuming by different object you mean different instances and not different implementations.
The key to this is scopes and how you manage your components. In particular ViewsApiComponent.
Let's start with scopes. A scope in dagger is nothing but an annotation that tells dagger that during the life of a given component, as long as an object annotated with a given scope is required, the instance provided will always be the same. In other words, within the same component scoped dependencies will be singleton.
In your code, this ActivityScope is the scope tied to ViewsApiEnd. Now what people usually don't get about scopes is the first part of - "... as long as the component is alive scoped dependencies are singleton". Basically this says, if your component's instance remains the same, then all your scoped instances will be the same.
In your code this is the case because you pin mViewsApiComponent to the application class and you never recreate it. So in your activities when you do this:
// ...
((MyApp) getApplication()).getGitHubComponent().inject(this);
// ...
You're always using the same component, hence same scopes, hence same instance of ViewsApiEnd.
You need to make sure the scoped dependencies have a proper scoped handling. If you want a dependency that is different per activity, then you want to manage the component that takes care of this dependency on a per activity basis.
There's different ways of doing this. I think the simplest one in your case is to move the creation of ViewsApiComponent to your activities. Make sure you nullify the component in onDestroy. Something like this:
private ViewsApiComponent mViewsApiComponent;
#Override
public void onCreate() {
super.onCreate();
getComponent().inject(this);
}
#Overrides
public void onDestroy() {
super.onDestroy();
mViewsApiComponent = null;
}
private ViewsApiComponent getComponent() {
if (mViewsApiComponent == null) {
mViewsApiComponent = DaggerViewsApiComponent.builder()
.httpComponent(((MyApp) getApplication()).getNetComponent())
.build();
}
return mViewsApiComponent;
}
You can even put this code in a base activity and inherit from it in each activity.
Important thing to notice is that the component is now managed by the activity, or better put it's tied to its life-cycle. This ensures the component lives during the life time of the activity and all scoped dependencies are the same within that activity. For another activity a new component will be created and the new object instances will be used, but within the activity they will remain the same.
Now I've explained all of this just for the sake of trying to help you out with components and scopes, but truth is that what you're currently providing in the component's modules are all objects that should indeed be singleton throughout the app's life. So in fact, the way you have it now is the most correct approach at least in my opinion.
Hope this helps
I'm starting to think in mvp, dagger should not be used in the presenter. The usual way to construct dagger is using a global component and have subcomponents for scoping the graph. This global component will take an applicationContext as a parameter on creating the appmodule.java class usually. Having the application context given makes life easier.
That's all fine but if I use a module from the global component or even a subcomponent, the context should be passed in. So that means if I inject the presenter with dagger it will be tied to the applicationContext. THIS MAKES IT DIFFICULT TO TEST as junit. Android code should not be in presenter.
So I'm asking is the best practice to just use dagger in activities fragments broadcast receivers and services only? Speaking in terms of mvp architecture that is. The other solution could be to design another dagger component but not a subcomponent that is not related to appcomponent or an applicationContext. What is the common practice?
UPDATE:
LETS look at a real example:
usually we'd create a appComponent that's close in application override like this:
public class MyApplication extends Application {
private AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = initDagger(this);
}
public AppComponent getAppComponent() {
return appComponent;
}
protected AppComponent initDagger(PomeloApplication application) {
return DaggerAppComponent.builder()
.appModule(new AppModule(application))
.build();
}}
and then for example in the presenter we'd do this in the constructor:
public WelcomePresenter(Context context) {
super(context);
presenterComponent = ((MyApplication) context).getAppComponent();
presenterComponent.inject(this);
}
so because I wanted the application Context for dagger providers I ended up forcing callers to depend on a context Object. Basically, you cant get the AppComponent modules until you get a context so you can cast it as "MyApplication" and inject from the component? So i was thinking why is this dagger pattern making me force the presenter to have a context?
Even if we used a subComponent it would still depend on the AppComponent and then in our test case we'd have to deal with an application context being created to get dagger to inject.
So I think there should be a rule - in MVP prefer manual constructor injection over dagger injection
Because class shouldn’t have knowledge about how it is injected. Something being injected should not care about how it is injected.
dagger.android outlines the problem i am talking about as per the accepted answer.
I also agree with the statement "Not having android related code in your presenter is always a good idea, and dagger does not interfere with that."
First, what I want to draw attention that starting from dagger version 2.10 you can use dagger.android package which simplifies injection in the activities and fragments, so you don't need to use MyApplication casting across the app.
Second, why are you not injecting WelcomePresenter into activity or fragment but vice versa?
Dependency injection is useful for Android components (activities, etc.) primarily because these classes must have a no-arg constructor so the framework can construct instances of them. Any class that isn't required to have a no-arg constructor should simply receive all its dependencies in its constructor.
Edit: A side note about how you're getting a reference to the AppComponent.
Application is-a Context, and the Context returned by Context#getApplicationContext() is usually the Application instance. But this is not necessarily the case. The one place I know of where it may not be the case is in an emulator. So this cast can fail:
presenterComponent = ((MyApplication) context).getAppComponent();
Mutable static fields are evil in general, and even more so on Android. But IMO, the one place you can get away with it is in your Application class. There is only one instance of Application, and no other component will ever exist before Application#onCreate() is called. So it's acceptable to make your AppComponent a static field of MyApplication, initialize it in onCreate(), and provide a static getter, as long as you only call the getter from the lifecycle methods of other components.