问题
I have been trying to implement Dagger2.
Problem: When I use constructor injection, it works fine but when I use field injection, it throws an Error like below:
Error:(6, 48) error: cannot find symbol class DaggerApplicationComponent
/home/moderator/Downloads/Maulik/Sample Codes/Made/Dagger2Demo/app/src/main/java/com/dagger2demo/dagger2demo/di/component/ApplicationComponent.java
Error:(18, 10) error: com.dagger2demo.dagger2demo.mvp.HomePresenter cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method. This type supports members injection but cannot be implicitly provided.
com.dagger2demo.dagger2demo.mvp.HomePresenter is injected at
com.dagger2demo.dagger2demo.mvp.BaseActivity.homePresenter
com.dagger2demo.dagger2demo.mvp.BaseActivity is injected at
com.dagger2demo.dagger2demo.di.component.ApplicationComponent.inject(baseActivity)
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.
Dagger2 - My Understanding: You have to create a Module class where you will create methods. These methods will give you respective object of your needed class like Retrofit, ApplicationContext etc.. You will create an component interface in which you will define where to inject module class's dependencies.
I'm using: Retrofit, RxJava - RaxAndroid, Dagger2 & MVP.
Code is below:
build.gradle(app)
// Retrofit Dependency
compile 'com.squareup.retrofit2:retrofit:2.3.0'
// Gson Converter Factory Dependency
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
// RxJava2 Adapter Dependency for Retrofit2
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
// ButterKnife Dependencies
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
// RxJava & RxAndroid Dependencies
compile group: 'io.reactivex.rxjava2', name: 'rxjava', version: '2.1.8'
compile group: 'io.reactivex.rxjava2', name: 'rxandroid', version: '2.0.1'
// Dagger2 Dependency
compile 'com.google.dagger:dagger:2.14.1'
annotationProcessor 'com.google.dagger:dagger-compiler:2.14.1'
Dagger2DemoApplication.java
public class Dagger2DemoApplication extends Application {
private ApplicationComponent mApplicationComponent;
@Override
public void onCreate() {
super.onCreate();
mApplicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule())
.build();
}
public ApplicationComponent getmApplicationComponent() {
return mApplicationComponent;
}
}
ApplicationModule.java
@Module
public class ApplicationModule {
@Provides
@Singleton
public APIEndPoints provideAPIEndPoints() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
APIEndPoints apiEndPoints = retrofit.create(APIEndPoints.class);
return apiEndPoints;
}
}
ApplicationComponent.java
@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(BaseActivity baseActivity);
}
BaseActivity.java
public class BaseActivity extends AppCompatActivity {
// Variables
public ProgressDialog mProgressDialog;
@Inject
HomePresenter homePresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// For Dagger2 i.e Creating instance of all provide methods defined in ApplicationModule
((Dagger2DemoApplication) getApplication()).getmApplicationComponent().inject(this);
setupProgressBar();
}
private void setupProgressBar() {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setTitle(getString(R.string.str_progress_dialog_title));
mProgressDialog.setMessage(getString(R.string.str_progress_dialog_desc));
mProgressDialog.setCancelable(false);
}
}
BaseView.java
public interface BaseView extends View {
void handleResponse(Object obj);
void showMessage(String msg);
}
View.java
public interface View {
}
BasePresenter.java
public interface BasePresenter {
void attachView(View view);
void callAPI();
}
HomePresenter.java
public class HomePresenter implements BasePresenter {
private BaseView mBaseView;
@Inject
APIEndPoints mApiEndPoints;
/*@Inject
public HomePresenter(APIEndPoints apiEndPoints) {
this.mApiEndPoints = apiEndPoints;
}*/
@Override
public void attachView(View view) {
mBaseView = (BaseView) view;
}
@Override
public void callAPI() {
// Actually calling API here with observable object - Start
Observable<Users> usersObservable = mApiEndPoints.getUsers();
usersObservable
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onSuccess, this::onError);
// Actually calling API here with observable object - End
}
private void onSuccess(Users users) {
mBaseView.handleResponse(users);
}
private void onError(Throwable throwable) {
mBaseView.showMessage(throwable.toString());
}
}
HomeActivity.java
public class HomeActivity extends BaseActivity implements BaseView {
// Widgets
@BindView(R.id.rv_users)
RecyclerView rv_users;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// For ButterKnife
ButterKnife.bind(this);
// Initializing Presenter
homePresenter.attachView(this);
}
public void getDataFromServer(View view) {
mProgressDialog.show();
homePresenter.callAPI();
}
// BaseView Methods
@Override
public void handleResponse(Object obj) {
Users users;
if (obj instanceof Users) {
users = (Users) obj;
if (users != null) {
mProgressDialog.dismiss();
rv_users.setLayoutManager(new LinearLayoutManager(HomeActivity.this));
rv_users.setAdapter(new RVAdapter(users.getData()));
}
}
}
@Override
public void showMessage(String msg) {
if (msg != null) {
mProgressDialog.dismiss();
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
}
As you can see I commented Constructor Injection in HomePresenter. I'm having Field Injection there instead. But I'm not able to build the project as I'm getting error like mentioned above.
Any help will be appreciated. Let me know if any other things related to code is required.
Thanks in advance.
EDIT: PS: I know the answer but I just can't understand why Field Injection i.e @Inject APIEndPoints mApiEndPoints; is not working in HomePresenter. Please someone explain me.
回答1:
As you can see I commented Constructor Injection in HomePresenter. I'm having Field Injection there instead.
If you use Constructor Injection, then Dagger will create the object for you and know all about it.
If you use field injection then you have to create the object and tell Dagger about it.
I don't see why you would prefer to use field injection in this case, but with field injection you need to add a @Provides
annotated method to one of your modules to give Dagger access to your presenter.
You need to use either Construcotr injection, or a @Provides
annotated methods in your module, just as the error states.
回答2:
You're confounding dependencies producer mechanism and dependencies consumption mechanism. An annotated field is used to consume a dependency. In your case, @Inject HomePresenter homePresenter
is telling Dagger "hey, I want you to inject an HomePresenter here". To do so, Dagger either needs you to define a @Provides
method or to have the object constructor annotated with @Inject
.
As a rule of thumb, always use @Inject
annotated constructor to provide dependencies. You should only use @Provides
method provider when the objects you're providing are either:
- an
interface
- an
abstract
class - an object coming from an external library (you don't have access to the constructor)
- an object which requires customization before being provided
In your case, you got your error because you don't have a @Provides
annotated method nor an @Inject
annotated constructor. You should uncomment your constructor as it is the way to go in your situation.
来源:https://stackoverflow.com/questions/48380865/dagger2-project-rebuild-error-field-injection-android