How to avoid adding an injection method for each view?

Currently, in order to get an instance, for example, Picasso in action, I need to add an add method to the AppComponent. How to avoid adding an injection method, because I have many fragments and views where it should be introduced:

AppComponent.class:

@ForApplication @Singleton @Component( modules = {AppModule.class,OkHttpClientModule.class,NetworkApiModule.class,NetworkAuthModule.class}) public interface AppComponent { void inject(Fragment1 obj); void inject(Fragment2 obj); void inject(Fragment3 obj); void inject(Fragment4 obj); void inject(Fragment5 obj); void inject(Fragment6 obj); ... } 

Fragment1.class

 public class Fragment1 extends Fragment { @Inject Picasso mPicasso; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyApplication.getComponent(getContext()).inject(this); } } 

My classes are:

AppModule.class:

 @Module public class AppModule { private MyApplication mApplication; public AppModule(@NonNull MyApplication mApplication) { this.mApplication = mApplication; } @Provides @NonNull @Singleton public Application provideApplication() { return mApplication; } @Provides @ForApplication Context provideContext(){ return mApplication; } @Provides @Singleton Picasso providesPicasso(@ForApplication Context context) { return new Picasso.Builder(context).build(); } } 

ForApplication.class:

 @Scope @Retention(RUNTIME) public @interface ForApplication { } 

Myapplication.class

 public class MyApplicationextends Application { static Context mContext; private AppComponent component; @Override public void onCreate() { super.onCreate(); mContext = this; setupComponent(); } private void setupComponent() { component = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); component.inject(this); } public AppComponent getComponent() { if (component==null) setupComponent(); return component; } public static AppComponent getComponent(Context context) { return ((MyApplication) context.getApplicationContext()).getComponent(); } 

UPDATE

I also want to add adapters for fragments, and if I add BaseFragment to the base, then BaseFragment will have all adapters for all child fragments

+7
java android dependency-injection dagger-2
source share
5 answers

I resolved it by adding a delegate class with lombok library

 @Accessors(prefix = "m") public class AdapterDelegate { @Getter @Inject Lazy<FlatAdapter> mFlatAdapterLazy; public AdapterDelegate(){ MyApplication.getComponent(MyApplication.getContext()).inject(this); } public static AdapterDelegate get() { return new AdapterDelegate(); } } 

And in action

 public class MainActivity extends Activity { FlatAdapter mFlatAdapter = AdapterDelegate.get().getFlatAdapterLazy().get(); 
0
source share

One solution would be to use inheritance for injection.

Just define a BaseFragment with an @Inject Picasso instance, create an injection method in the DaggerComponent for that BaseFragment, and call it in the onCreate BaseFragment method. More specific fragments, such as Fragment1, 2 .., can inherit this BaseFragment and use a Picasso instance.

+2
source share

How about this?

 public final class MySimpleDelegate { @Inject protected Picasso picasso; @Inject protected Lazy<AdapterOne> lazyAdapterOne; @Inject protected Provider<AdapterTwo> providerAdapterTwo; public MySimpleDelegate(Context context) { MyApplication.getComponent(context).inject(this); } @NonNull public void getPicasso() { return picasso; } @NonNull AdapterOne getAdapterOne() { // the object is injected when the following method is called return lazyAdapterOne.get(); } @NonNull AdapterTwo getAdapterTwo() { // a new instance is created every time this methos is called return providerAdapterTwo.get(); } } public class Fragment1 extends Fragment { private MySimpleDelegate delegate; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); delegate = new MySimpleDelegate(getContext()); Picasso picasso = delegate.getPicasso(); AdapterOne one = delegate.getAdapterOne(); AdapterTwo two = delegate.getAdapterTwo(); } } 

By the way, if Picasso is the only problem, it also provides the setSingletonInstance method. See this link

EDIT

I believe that you can achieve what you want using a dagger provider or lazy factories. See the example above.

+1
source share

The solution is that you can inherit ex: use the Activity or Fragment extension and do the injection in onCreate () in these classes

Below is an example of what I am doing:

Graph.java

 @Singleton @Component(modules = { AppModule.class, }) public interface Graph { void inject(BaseActivity activity); void inject(BaseFragment fragment); } 

BaseActivity.java

 public class BaseActivity extends AppCompatActivity { protected List<Subscription> mSubscriptions; @Inject protected SharedDB dm; @Inject protected RestApi restApi; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getGraph().inject(this); } public Graph getGraph() { return MyApplication.graph(this); } //... } 

Basefragment.java

 public class BaseFragment extends Fragment { protected List<Subscription> mSubscriptions; protected Unbinder unbinder; @Inject protected SharedDB dm; @Inject protected RestApi restApi; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getGraph().inject(this); } public Graph getGraph() { return MyApplication.graph(getActivity()); } //.... } 

Myapplication.java

 public class MyApplication extends Application { private Graph mGraph; @Override public void onCreate() { super.onCreate(); setGraph(DaggerGraph.builder() .appModule(new AppModule(this)) .build()); } public Graph getGraph() { return mGraph; } public void setGraph(Graph graph) { mGraph = graph; } public static Graph graph(Context context) { DominoApp app = (DominoApp) context.getApplicationContext(); return app.getGraph(); } //.... } 
+1
source share

You cannot avoid adding an injection method for each target class in a flat way, but you can avoid calling this injection method in each class using reflection. With this solution, you can only call the injection method in the parent class, and then ComponentReflectionInjector will provide dependencies for each child class in the inheritance chain.

How will it look like:

 Component { void inject(Child b); } //Activity, fragment - no matter class Parent { ComponentReflectionInjector componentReflectionInjector; void onCreate() { componentReflectionInjector = new ComponentReflectionInjector(Component.class, /* component instance*/); componentReflectionInjector.inject(this); } } //your fragment with Picasso class Child extends Parent { @Inject MyDependency dependency; } 

And then the dependencies would be available in the onCreate method of the Child class.

This very controversial decision would cost for convenience to lose some performance and would cost some potential problems with ProGuard after obfuscation, and dagger2 were designed to not use reflection at all in DI, but still.

-one
source share

All Articles