I am trying to figure out how to use Dagger components/subcomponents. I know it is the older style of things but I have a legacy app that is using this Dagger structure and I'm using this sample project to better understand it.
This sample app has just a AppComponent, AppModule, ActivityComponent and ActivityModule. I'm trying to inject MainActivityDependency into my MainActivity but the compiler says it can provide it without an explicit #Provides. But I am already explicitly providing it. I know I can just annotate the class with #Inject but for the sake of exercise I need to use the #Provides method.
It seems like I have the dependency structure correct but can't figure it out. I've pasted sample code below but here is the github link as well:
https://github.com/fkruege/daggerSubComponentPractice/tree/master/app/src/main/java/com/franctan/daggerpractice
Thank you
AppComponent.java
#Singleton
#Component(modules = AppModule.class)
public interface AppComponent {
ActivityComponent.Builder activityComponentBuilder();
Application application();
void inject(MyApp myApp);
}
AppModule
#Module(subcomponents = {ActivityComponent.class})
public class AppModule {
private Application app;
public AppModule(Application app) {
this.app = app;
}
#Provides
#Singleton
public Application provideApplication() {
return app;
}
#Provides
#Singleton
public AppDependency provideAppDependency() {
return new AppDependency();
}
}
ActivityComponent
#ActivityScope
#Subcomponent(modules = ActivityModule.class)
public interface ActivityComponent {
#Subcomponent.Builder
interface Builder {
Builder activityModule(ActivityModule module);
ActivityComponent build();
}
void inject(MainActivity mainActivity);
}
ActivityModule
#Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
#ActivityScope
#Provides
public Activity provideActivity() {
return activity;
}
#ActivityScope
#Provides
public MainActivityDependency provideMainActivityDependency() {
return new MainActivityDependency();
}
}
MyApp
public class MyApp extends Application {
public AppComponent appComponent;
#Inject
AppDependency appDependency;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent
.builder()
.appModule(new AppModule(this))
.build();
appComponent.inject(this);
}
}
MainActivity
#Inject
MainActivityDependency mainActivityDependency;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApp myApp = (MyApp) getApplication();
myApp.appComponent
.activityComponentBuilder()
.activityModule(new ActivityModule(this))
.build()
.inject(this);
So figured it out. It turns out the ActivityScope interface was defined incorrectly:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Scope
public #interface ActivityScope {
}
The #Qualifier annotation was messing things up. Dumb mistake.
Related
I'm really confused about dagger 2. There are so many different ways people provide a solution. How can i inject my application to provide my database?
I already have my database module, an application module that provide my application. my applicationComponent with a builder inside it (have no idea what it does). With that builder it is not possible to build it inside my application class!?
Application class:
public class OnSiteApplication extends Application implements HasActivityInjector {
#Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}
AppComponent:
#Singleton
#Component(modules = {ApplicationModule.class, AndroidInjectionModule.class})
public interface AppComponent extends AndroidInjector<OnSiteApplication> {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(OnSiteApplication onSiteApplication);
}
Application Module:
#Module(includes = DatabaseModule.class)
public class ApplicationModule {
private static final String SHARED_PREFERENCE_NAME = "OnSitePreferences";
private final OnSiteApplication application;
public ApplicationModule(OnSiteApplication appContext) {
this.application = appContext;
}
#Provides
public OnSiteApplication provideOnSiteApplication() {
return application;
}
}
Database Module:
#Module
public class DatabaseModule {
#Provides
public static OnSiteDatabase provideDatabase(Application appContext) {
return Room.databaseBuilder(appContext,
OnSiteDatabase.class, OnSiteDatabase.DATABASE_NAME)
.fallbackToDestructiveMigration()
.build();
}
#Provides
public static ProjectDao provideProjectAccess(OnSiteDatabase onSiteDatabase) {
return onSiteDatabase.projectDao();
}
}
Most of the solution are one year or older. What is the most modern way of injecting OS based classes like Application?
In your implementation there are some problems:
Problem - 1:
You provide DatabaseModule as dependency to ApplicationModule which is not correct as DatabaseModule never used inside ApplicationModule. Rather you can pass
ApplicationModule to DatabaseModule as application context is used to create database. [But which is not required, check below]
Problem - 2:
Here ApplicationModule is useless as Application is already provided through #BindsInstance. So you can delete ApplicationModule from here.
So final implementation looks like:
#Singleton
#Component(modules = {DatabaseModule.class, AndroidInjectionModule.class})
public interface AppComponent extends AndroidInjector<OnSiteApplication> {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(OnSiteApplication onSiteApplication);
}
And OnSiteApplication, Create the AppComponent like below:
public class OnSiteApplication extends Application implements HasActivityInjector {
#Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder().application(this).build();
}
public AppComponent getAppComponent() {
return appComponent;
}
#Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}
I am using dagger 2 and retrofit
I have Two Modules
1.Application Module
2.BlogModule
#Module
public class BlogModule {
#PerActivity
#Provides
ApiService provideApiService(Retrofit retrofit){
return retrofit.create(ApiService.class);
}
}
ApplicationComponent
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
Retrofit exposeRetrofit();
Context exposeContext();
}
And I have added dependency in BlogComponent
#PerActivity
#Component(modules = BlogModule.class,dependencies = ApplicationComponent.class)
public interface BlogComponent {
void inject(BaseActivity mainActivity);
}
And in My Application
public class BlogApplication extends Application {
private ApplicationComponent mApplicationComponent;
#Override
public void onCreate() {
super.onCreate();
initializeApplicationComponent();
}
private void initializeApplicationComponent() {
mApplicationComponent= DaggerApplicationComponent
.builder().applicationModule(new ApplicationModule(this))
.build();
}
public ApplicationComponent getApplicationComponent(){
return mApplicationComponent;
}
When I try to inject BlogComponent in My Base Actvity I cant able to add getApplicationComponent() in applicationComponent(getApplicationComponent())
DaggerBlogComponent.builder()
.applicationComponent()
.blogModule(new BlogModule())
.build().inject(this);
As per tutorial they have injected as below
DaggerCakeComponent.builder()
.applicationComponent(getApplicationComponent())
.cakeModule(new CakeModule(this))
.build().inject(this);
Can any one help me how I can fix this.thanks
You should be able to access it from your application
DaggerBlogComponent.builder()
.applicationComponent(((BlogApplication)getApplication()).getApplicationComponent())
.blogModule(new BlogModule())
.build().inject(this);
Looking at some examples I was able to work with Dagger 2.11 for activities and fragments, however, I'm not getting any progress when creating modules for calls to Webservice using Retrofit + RxJava. Sorry if it is a repeated question, I have not found solution here.
Follow my application code below:
App.java
public class App extends Application implements HasActivityInjector {
#Inject
DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;
#Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.builder().create(this).inject(this);
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
} else {
Fabric.with(this, new Crashlytics());
Timber.plant(new FirebaseCrashReportingTree());
}
}
#Override
public AndroidInjector<Activity> activityInjector() {
return activityDispatchingAndroidInjector;
}
}
AppComponent.java
#Singleton
#Component(modules = {
AppModule.class})
interface AppComponent extends AndroidInjector<App> {
#Component.Builder
abstract class Builder extends AndroidInjector.Builder<App> {
}
}
AppModule.java
#Module(includes = {AndroidInjectionModule.class})
abstract class AppModule {
#Binds
#Singleton
abstract Application application(App app);
#PerActivity
#ContributesAndroidInjector(modules = MainActivityModule.class)
abstract MainActivity mainActivityInjector();
}
I am trying my hands on Dependancy Injection using Dagger2.
It gives error in build phase and says cannot inject SharedPreference instance.
Here are my modules and components.
Application Module
#Module
public class ApplicationModule {
private Application app;
private String PREF_NAME = "prefs";
public ApplicationModule(Application app) {
this.app = app;
}
#Singleton
#Provides
public Picasso getPicasso() {
return new Picasso.Builder(app).build();
}
#Singleton
#Provides
public SharedPreferences getAppPreferences() {
return app.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
}
}
ApplicationComponent
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(App app);
}
App.java
public class App extends Application {
ApplicationComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
createDaggerInjections();
}
public ApplicationComponent getAppComponent() {
return appComponent;
}
public static App getAppInstance(Context context) {
return (App) context.getApplicationContext();
}
private void createDaggerInjections() {
appComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
appComponent.inject(this);
}
}
Login Module
#Module
public class LoginModule {
LoginView view;
public LoginModule(LoginView view) {
this.view = view;
}
#Provides LoginView getLoginView()
{
return view;
}
#Provides LoginPresenter getLoginPresenter(LoginView view)
{
return new LoginPresenterImpl(view);
}
}
LoginComponent
#ActivityScope
#Component(
dependencies = ApplicationComponent.class,
modules = LoginModule.class)
public interface LoginComponent {
void inject(LoginActivity activity);
LoginPresenter getLoginPresenter();
}
LoginActivity.java
public class LoginActivity extends BaseActivity implements LoginView {
private static final String TAG = "LoginActivity";
#Inject
SharedPreferences prefs;
-----
-----
-----
#Override
public void createDaggerInjections() {
DaggerLoginComponent.builder().applicationComponent(App.getAppInstance(this).getAppComponent())
.loginModule(new LoginModule(this))
.build();
}
This line #Inject
SharedPreferences prefs; gives error which is as follows. The same error comes when I try to inject Picasso Instance also.
/home/blackidn/proj/styling android 3/dagger 2/DaggerEx/app/src/main/java/com/mohammad/daggerex/App/App.java:8: error: cannot find symbol
import com.mohammad.daggerex.dagger.DaggerApplicationComponent;
^
symbol: class DaggerApplicationComponent
location: package com.mohammad.daggerex.dagger
/home/blackidn/proj/styling android 3/dagger 2/DaggerEx/app/src/main/java/com/mohammad/daggerex/ui/Login/LoginComponent.java:16: error: android.content.SharedPreferences cannot be provided without an #Provides- or #Produces-annotated method.
void inject(LoginActivity activity);
^
com.mohammad.daggerex.ui.Login.LoginActivity.prefs
[injected field of type: android.content.SharedPreferences prefs]
Stucked with this and Don't know how to solve this and move forward. What am I missing ? Any help would be great.
You should expose SharedPreferences to LoginComponent in ApplicationComponent. Otherwise, you can't inject it.
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(App app);
SharedPreferences sharedPreferences();
}
Dagger 2 update :
The #Subcomponent could be used without any need to do this as can be seen here for the context: (ChatComponent is a subcomponent with custom scope)
from this excellent article:
https://proandroiddev.com/dagger-2-part-ii-custom-scopes-component-dependencies-subcomponents-697c1fa1cfc
Just started using Dagger 2 today and I'm a bit confused on how exactly I need to set everything up.
I'm trying to inject a POJO, but it's always null.
First, some code:
App.java
private AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent
.builder()
.appModule(new AppModule(this))
.build();
}
public AppComponent component() {
return appComponent;
}
AppModule.java
#Module
public class AppModule {
private Application app;
public AppModule(Application app) {
this.app = app;
}
#Provides #Singleton
public Application application() {
return app;
}
}
AppComponent.java
#Singleton
#Component(modules = AppModule.class)
public interface AppComponent {
void inject(App application);
Application application();
}
NetworkingManager.java
#Singleton
public class NetworkingManager {
private Context ctx;
#Inject
public NetworkingManager(Context context) {
this.ctx = context;
}
}
NetModule.java
#Module
public class NetModule {
#Provides #Singleton
public NetworkingManager provideNetworkingManager(Application application) {
return new NetworkingManager(application);
}
}
NetComponent.java
#Singleton
#Component(modules = {NetModule.class},
dependencies = {AppModule.class})
public interface NetComponent {
void inject(NetworkingManager networkingManager);
}
SomeClass.java
#Inject
NetworkingManager networkingManager;
public void doSomethingWithNetworkManager() {
networkManager.doStuff();
}
I've spent a good deal of time looking through lots of tutorials, SO questions, and examples, but I haven't been able to figure out what I'm doing wrong.
I'm 99% certain I have something setup wrong, but I haven't been able to figure out what.
Based on your comment, you want to make NetworkingManager available everywhere in your application.
Let's start with your definition of the Component:
#Singleton
#Component(modules = AppModule.class)
public interface AppComponent {
void inject(App application);
}
This tells Dagger that this component will be injecting the App class. Now here you can also tell Dagger other classes you would like to inject. So if you want to also inject an Activity for example you would add:
#Singleton
#Component(modules = AppModule.class)
public interface AppComponent {
void inject(App application);
void inject(MainActivity activity) //Where MainActivity is a class that extends Activity.
}
Please note that this is not the best way, IMO, to share Application wide dependencies; you should create a Component that inherits from AppComponent and make AppComponent expose the desired shared dependencies.
Now let's look at your module class:
#Module
public class NetModule {
#Provides #Singleton
public NetworkingManager provideNetworkingManager(Application application) {
return new NetworkingManager(application);
}
}
Here you are #Provideing a NetworkingManager, that is fine. Your NetworkingManager requires an Application (a Context really), why not provide App inside of NetworkingManager?, or even better why not provide NetworkingManager inside the AppModule since AppModule should #Provide things that are common for the whole Application:
#Module
public class AppModule {
private Application app;
public AppModule(Application app) {
this.app = app;
}
#Provides #Singleton
public Application application() {
return app;
}
#Provides #Singleton
public NetworkingManager provideNetworkingManager(Application application) {
return new NetworkingManager(application);
}
}
Now inside your App class:
public class App extends Application {
private AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent
.builder()
.appModule(new AppModule(this))
.build();
appComponent.inject(this);
}
public AppComponent component() {
return appComponent;
}
}
And in our hypothetical MainActivity:
public class MainActivity extends Activity {
private AppComponent appComponent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
appComponent = ((App)getApplicationContext()).getAppComponent();
appComponent.inject(this);
}
}
It seems that you are not using #Component(dependencies = {...}) correctly. dependencies is used when you want to expose a dependency from one Component to another using the mechanism I mentioned above.