Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependencies from two components in one activity

I'm playing with Dagger-2 to figure how to integrate it in our existing application and I'm facing something which I can't understand or I'm doing wrong.

My situation :

3 API without any annotated constructor ( each one in its own file )

public class DbApi {
   public void doSomething(String username, String password) {
   }
}

public class RestApi {
    public void doSomething(String username, String password) {
    }
}

public class SocketApi {
    public void doSomething(String username, String password) {
    }
}

3 Modules ( each one in its own file )

@Module
public class DbModule {
    @Provides
    @Singleton
    public DbApi getDbApi(){
        return new DbApi();
    }
}

@Module
public class RestModule {
    @Provides
    @Singleton
    public RestApi getRestApi(){
        return new RestApi();
    }
}

@Module
public class SocketModule {
    @Provides
    @Singleton
    public SocketApi getSocketApi(){
        return new SocketApi();
    }
}

2 Components ( each one in its own file )

@Singleton
@Component(modules = {DbModule.class})
public interface DbComponent {
   void inject(SecondActivity activity);
}

@Singleton
@Component(modules = {RestModule.class, SocketModule.class})
public interface NetComponent {
   void inject(MainActivity activity);
}

I initialize the two components into my Aplication

public class MyApplication extends Application {

DbComponent dBComponent;
NetComponent netComponent;

@Override
public void onCreate() {
    super.onCreate();
    dBComponent = DaggerDbComponent.builder().build();
    netComponent = DaggerNetComponent.builder().build();
}

public NetComponent getNetComponent() {
    return netComponent;
}

public DbComponent getdBComponent() {
    return dBComponent;
}
}

With all this defined I use the NetComponent into one activity and the DbCompoment into a second one.

Into the first activity

public class MainActivity extends AppCompatActivity {

@Inject RestApi restApi;
@Inject SocketApi socketApi;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //...
    ((MyApplication) getApplication()).getNetComponent().inject(this);
    //...
}
}

and into the second

public class SecondActivity extends AppCompatActivity {

@Inject DbApi dbApi;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //...
    ((MyApplication) getApplication()).getdBComponent().inject(this);
    //...
}
}

Up to here everything works fine and I got my stuff injected properlty in each activity. But then I have realised that RestApi and SocketApi were also required into the SecondActity so I tried to inject them into the activity and here I have doubts and issues.

I modify my NetComponent to add the following line

void inject(SecondActivity activity);

And I modify my SecondActivity

public class SecondActivity extends AppCompatActivity {

@Inject DbApi dbApi;
@Inject RestApi restApi;
@Inject SocketApi socketApi;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //...
    ((MyApplication) getApplication()).getdBComponent().inject(this);
    ((MyApplication) getApplication()).getNetComponent().inject(this);
    //...
}
}

After those modifications compiling my project I have the following error

Error:(15, 10) error: com.example.guillaume.testdagger.RestApi cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method. com.example.guillaume.testdagger.SecondActivity.restApi [injected field of type: com.example.guillaume.testdagger.RestApi restApi]

Error:(16, 10) error: com.example.guillaume.testdagger.DbApi cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method. com.example.guillaume.testdagger.SecondActivity.dbApi [injected field of type: com.example.guillaume.testdagger.DbApi dbApi]

So my questions are :

  • Where this error comes from?
  • How can I use several components to inject fields into one activity
  • Am I doing this wrong and what will be the best way to organize components/modules in order to be able to reuse one compoment into an activity already containing another module
  • I can fix the error by adding and empty public constructor annotated with @Inject to my api classes but doing this I discoreved that all my fields will be injected into the SecondActivity regardless of the component used to invoke the inject method, is it the right way to do this.
like image 730
Guillaume Barré Avatar asked Apr 01 '16 09:04

Guillaume Barré


Video Answer


1 Answers

Ah...I share your pain. You can't inject two components into same Activity. At least I was not able to find how! :)

That was logical for me to try, as well, and I faced same problems.

You can resolve it with 2 approach:

  1. Use one big component for all injections (I am really agains that)
  2. Create one component for each Activity/place you want to inject something

So, instead of

@Singleton
@Component(modules = {RestModule.class, SocketModule.class})
public interface NetComponent {
   void inject(MainActivity activity);
}

try with

@Singleton
@Component(modules = {RestModule.class, SocketModule.class, DbModule.class})
public interface SecondActivityComponent {
   void inject(SecondActivity activity);
}

I found second one as cleanest solution.

If anybody has some other advice, I am ready to try it!

like image 132
Bozic Nebojsa Avatar answered Sep 19 '22 02:09

Bozic Nebojsa