Reputation: 21
I'm relatively new to Dagger 2, and I kept running into compiler error from Dagger 2 says missing @Provide
or @Produces
. What I'm trying to do is inject common components in base class, then child class also has its own component. I checked out several examples online and saw people using sub-component; but I still don't get why can we just have multiple independent components for each class? I don't see why my ImageComponent
has to be sub-component of ApiComponent
, it just doesn't make any sense. So I'm wondering what's the right approach regarding this issue, or is there any alternative approach that I'm not aware of? Thanks.
Api Component
public interface UserApi {
int getUser();
}
public interface SearchApi {
int search();
}
@Singleton
@Module
public class ApiModule {
public ApiModule() {
}
@Singleton
@Provides
public SearchApi provideSearchApi() {
return new SearchApi() {
@Override
public int search() {
return 0;
}
};
}
@Singleton
@Provides
public UserApi provideUserApi() {
return new UserApi() {
@Override
public int getUser() {
return 0;
}
};
}
}
@Singleton
@Component(modules = {
ApiModule.class
})
public interface ApiComponent {
void inject(BaseActivity activity);
}
Image Component
public interface ImageLoader {
boolean load(String url);
}
@ActivityScope
@Module
public class ImageModule {
@ActivityScope
@Provides
public ImageLoader provideImageResource() {
return new ImageLoader() {
@Override
public boolean load(String url) {
return false;
}
};
}
}
@ActivityScope
@Component(
modules = {
ImageModule.class
}
)
public interface ImageComponent {
// Dagger doesn't allow this? Not sure why?
void inject(MainActivity activity);
}
Activity and Components Singleton
public class Components {
private ApiComponent apiComponent;
private ImageComponent imageComponent;
private static Components singleton;
public static void initialize(Context context) {
if (singleton != null) {
throw new RuntimeException("Attempted to initialize components twice");
}
singleton = new Components(context);
}
public static Components get() {
return singleton;
}
private Components(Context context) {
apiComponent = ApiComponent
.builder()
.dataModule(new ApiModule())
.build();
// Can't generate image component yet
}
public ApiComponent api() {
return apiComponent;
}
public ImageComponent image() {
return imageComponent;
}
}
public abstract class BaseActivity extends AppCompatActivity {
@Inject
protected UserApi userApi;
@Inject
protected SearchApi searchApi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Components.get().data().inject(this);
}
}
public class MainActivity extends BaseActivity {
@Inject
protected ImageLoader imageLoader;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
stacktrace
Error:(15, 10) error: android.com.dagger.data.UserApi cannot be provided without an @Provides- or @Produces-annotated method.
android.com.dagger.BaseActivity.userApi
[injected field of type: android.com.dagger.data.UserApi userApi]
Upvotes: 2
Views: 1154
Reputation: 8277
base classes are not sufficient as injection targets. Dagger 2 relies on strongly typed classes, so you must specify explicitly which ones should be defined
You can't do this Components.get().data().inject(this);
this
(i.e BaseActivity
is abstract)
Upvotes: 4