dagger2 injection not working - SharedPreferences - android

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

Related

Dagger 2 Dependency Injection

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

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.

I don't know why the object injected by dagger2 is null in presenter

I don't know why loginResponseHandler of MainRankPresenter.java injected by dagger2 is null in MainRankPresenter.
I just want to inject to field for field injection.
Should I do other way instead field injection?
please, Let me know how to resolve it.
BBBApplication.java
public class BBBApplication extends MultiDexApplication
{
...
#Override
public void onCreate() {
super.onCreate();
initAppComponent();
}
private void initAppComponent() {
this.appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}
public static BBBApplication get(Context ctx) {
return (BBBApplication) ctx.getApplicationContext();
}
public AppComponent getAppComponent() {
return this.appComponent;
}
...
}
AppModule.java
#Module
public class AppModule {
private BBBApplication application;
public AppModule(BBBApplication application) {
this.application = application;
}
#Provides
#Singleton
public Application provideApplication() {
return this.application;
}
#Provides
#Singleton
public Resources provideResources() {
return this.application.getResources();
}
#Provides`enter code here`
#Singleton
public SharedPreferences provideSharedPreferences() {
return PreferenceManager.getDefaultSharedPreferences(this.application);
}
}
AppComponent.java
#Singleton
#Component(modules = {AppModule.class, ServiceModule.class})
public interface AppComponent {
RankFragmentComponent plus(RankFragmentModule module);
Application application();
Resources resources();
}
RankFragmentModule.java
#Module
public class RankFragmentModule {
private RankFragment rankFragment;
public RankFragmentModule(RankFragment rankFragment) {
this.rankFragment = rankFragment;
}
#Provides
#ActivityScope
public LoginResponseHandler provideLoginResponseHandler() {
return new LoginResponseHandler(this.rankFragment);
}
#Provides
#ActivityScope
// #Named("rankFragment")
public RankFragment provideRankFragment() {
return this.rankFragment;
}
#Provides
#ActivityScope
public MainRankPresenter provideMainRankPresenter(RankFragment rankFragment) {
return new MainRankPresenter(new MainRankViewOps(rankFragment));
}
}
RankFragmentComponent.java
#ActivityScope
#Subcomponent(modules = {RankFragmentModule.class})
public interface RankFragmentComponent {
void inject(RankFragment rankFragment);
}
RankFragment.java
public class RankFragment extends Fragment {
#Inject
MainRankPresenter presenter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BBBApplication.get(getContext())
.getAppComponent()
.plus(new RankFragmentModule(this))
.inject(this);
presenter.test();
}
MainRankPresenter.java
public class MainRankPresenter implements Presenter {
private MainRankViewOps viewOps;
#Inject
LoginResponseHandler loginResponseHandler;
#Inject
public MainRankPresenter(MainRankViewOps viewOps) {
this.viewOps = viewOps;
}
#Override
public void test() {
Log.d(Constants.TAG_DEBUG, "=== presenter test" + this.toString());
Log.d(Constants.TAG_DEBUG, "=== " + loginResponseHandler.toString());
this.viewOps.initViewOps();
}
}
MainRankViewOps.java
public class MainRankViewOps implements ViewOps {
RankFragment fragment;
#Inject
public MainRankViewOps(RankFragment fragment) {
this.fragment = fragment;
}
#Override
public void initViewOps() {
Log.d(Constants.TAG_DEBUG, "=== view ops" + this.toString());
Log.d(Constants.TAG_DEBUG, "=== " + fragment.toString());
}
}
Injection by Dagger 2 is not recursive. Therefore, when you call inject(this) in RankFragment only #Inject annotated fields of that fragment are being injected. Dagger 2 will not search for #Inject annotations in the injected objects.
In general, you should attempt to restrict usage of Dependency Injection frameworks to "top-level" components (Activities, Fragments, Services, etc.) which are being instantiated by Android framework for you. In objects that you instantiate yourself (like MainRankPresenter) you should use other DI techniques which do not involve external framework (e.g. dependency injection into constructor).
Because you #Provides the MainRankPresenter, Dagger won't inject it: you take responsibility for this. You could possibly have your provides method be passed a MembersInjector si you can inject the fields if the object before returning it, but it'd probably be better to refactor your module you remove that provides method and let Dagger handle the injection (you have all the #Inject needed already)

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