How to inject my application class for Room - android

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;
}
}

Related

Dagger2 conversion to android.dagger

I studied some tutorials about new dagger.android approach but can't make it right. I built a simple tutorial with subcomponent builder but i can't convert this to new approach. All tutorials and articles leave required parts empty.
This example is for learning purposes may not be suitable for practical situations and i only intended implementing field injection, constructor injection may be more appropriate.
Scope
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ActivityScope {
}
Parent Component
#Component(modules = ApplicationModule.class)
#Singleton
public interface ApplicationComponent {
// Calls SubComponent Builder from MainActivity using ApplicationComponent
ToastMakerSubComponent.Builder toastMakerBuilder();
}
Parent Module, i didn't use #BindsInstance in app module for learning different approaches
#Module(subcomponents = {ToastMakerSubComponent.class})
public class ApplicationModule {
private Context context;
public ApplicationModule(Context context) {
this.context = context;
}
#Provides
#Singleton
SharedPreferences provideSharedPreferences() {
System.out.println("ApplicationModule context: " + context);
return context.getSharedPreferences("PrefName", Context.MODE_PRIVATE);
}
}
Sub Component
#ActivityScope
#Subcomponent(modules = {ToastMakerModule.class})
public interface ToastMakerSubComponent {
void inject(MainActivity mainActivity);
/*
Builder is called from Parent Component,
and parent component is called from scope(Activity, Fragment, etc.)
*/
#Subcomponent.Builder
interface Builder {
ToastMakerSubComponent build();
#BindsInstance
Builder context(Context context);
}
}
Sub Component Module
#Module
public class ToastMakerModule {
#ActivityScope
#Provides
ToastMaker provideToastMaker(Context context) {
System.out.println("ToastMakerModule context: " + context);
return new ToastMaker(context);
}
}
Instantiate ApplicationComponent inside MyApplication
mApplicationComponent = DaggerApplicationComponent
.builder()
.applicationModule(new ApplicationModule(getApplicationContext()))
.build();
And get sub component inside Activity
ApplicationComponent applicationComponent = ((MyApplication) getApplication()).getApplicationComponent();
ToastMakerSubComponent toastMakerSubComponent = applicationComponent
.toastMakerBuilder()
.context(this)
.build();
toastMakerSubComponent.inject(this);
After following this, this, and this tutorial i built the following as
#Component(modules = ApplicationModule.class)
#Singleton
public interface ApplicationComponent {
// What should i put here ???
}
Parent module but i didn't get how i should provide provideSharedPreferences
#Module(subcomponents = {ToastMakerSubComponent.class})
abstract class ApplicationModule {
#Binds
#IntoMap
#ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends MainActivity>
bindYourActivityInjectorFactory(ToastMakerSubComponent.Builder builder);
}
Sub component is missing ToastMakerSubComponent build(); and #BindsInstance Builder context(Context context); how should i add these to this component.
#ActivityScope
#Subcomponent(modules = {ToastMakerModule.class})
public interface ToastMakerSubComponent extends AndroidInjector<MainActivity> {
// ??? Is this required?
void inject(MainActivity mainActivity);
#Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
???
}
}
Also i see #ContributesAndroidInjector, where does it fit in this example?
Here's the diff of changes: https://www.diffchecker.com/3IL8UQ7P
Make app component extend AndroidInjector<MyApplication> and include the AndroidSupportInjectionModule
#Component(modules = {ApplicationModule.class, AndroidSupportInjectionModule.class})
#Singleton
public interface ApplicationComponent extends AndroidInjector<MyApplication> {
}
Make the subcomponent extend AndroidInjector<MainActivity> and the builder AndroidInjector.Builder<MainActivity>, use seedInstance to provide arguments to #BindsInstance methods.
#ActivityScope
#Subcomponent(modules = {ToastMakerModule.class})
public interface ToastMakerSubComponent extends AndroidInjector<MainActivity> {
#Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
#Override
public void seedInstance(MainActivity instance) {
context(instance);
}
#BindsInstance
public abstract Builder context(Context context);
}
}
Add a binding for the subcomponent builder to a module installed in the app component:
#Module(subcomponents = {ToastMakerSubComponent.class})
public abstract class ApplicationModule {
private Context context;
public ApplicationModule(Context context) {
this.context = context;
}
#Provides
#Singleton
SharedPreferences provideSharedPreferences() {
System.out.println("ApplicationModule context: " + context);
return context.getSharedPreferences("PrefName", Context.MODE_PRIVATE);
}
#Binds
#IntoMap
#ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity> bindMainActivityFactory(ToastMakerSubComponent.Builder builder);
}
Let framework classes extend the Dagger* counterparts, or implement Has*Injector interfaces if you can't use inheritance
public class MyApplication extends DaggerApplication {
#Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerApplicationComponent.create();
}
}
public class MainActivity extends DaggerAppCompatActivity {
#Inject
SharedPreferences sharedPreferences;
#Inject
ToastMaker toastMaker;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toastMaker.showToast("sharedPreferences " + sharedPreferences);
}
}

RequestQueue cannot be provided without an inject constructor

I am trying to learn Dagger2 from this medium article and pass RequestQueue as an activity level dependency:
https://proandroiddev.com/dagger-2-annotations-binds-contributesandroidinjector-a09e6a57758f
I can create application components just fine but I am facing a lot of trouble with ContributesAndroidInjector.
Application Class:
public class PokemonApplication extends Application {
private static AppComponent appComponent;
public static AppComponent getAppComponent(){
return appComponent;
}
#Override
public void onCreate() {
super.onCreate();
appComponent=buildMyComponent();
}
private AppComponent buildMyComponent() {
return DaggerAppComponent.builder().appmod(this).build();
}
}
AppModule:
#Module
public abstract class AppModule {
#ContributesAndroidInjector(modules = VolleyModule.class)
abstract MainActivity mainActivity();
#Provides
#Singleton
static SharedPreferences providePreferences(Application application) {
return application.getSharedPreferences("data", Context.MODE_PRIVATE);
}
#Provides
#Singleton
static Context getContext(Application application){
return application.getApplicationContext();
}
}
AppComponent:
#Singleton
#Component(modules = {RetrofitModule.class,AppModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity); //Error here.
#Component.Builder
interface Builder
{
AppComponent build();
#BindsInstance Builder appmod(Application application);
}
}
VolleyModule:
#Module
public abstract class VolleyModule {
#Provides
static RequestQueue getRequestQueue(Context context) {
return Volley.newRequestQueue(context);
}
}
MainActivity:
#Inject
RequestQueue requestQueue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PokemonApplication.getAppComponent().inject(this);
VolleyModule has to be also declared in the list of modules in your Component
#Singleton
#Component(modules = {RetrofitModule.class,AppModule.class, VolleyModule.class})

Dagger component & subcomponents

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.

Dagger 2.11, difficulty when create new module for retrofit and rxjava

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();
}

Android Dagger 2 POJO field Inject null

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.

Categories

Resources