【问题标题】:Dagger2 - Project Rebuild Error - Field Injection - AndroidDagger2 - 项目重建错误 - 字段注入 - Android
【发布时间】:2018-01-22 11:46:03
【问题描述】:

我一直在尝试实现 Dagger2。

问题:当我使用构造函数注入时,它可以正常工作,但是当我使用字段注入时,它会抛出如下错误:

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 - 我的理解:您必须创建一个 Module 类,您将在其中创建方法。这些方法将为您提供所需类的相应对象,如 Retrofit、ApplicationContext 等。您将创建一个组件接口,您将在其中定义注入模块类的依赖项的位置。

我正在使用:Retrofit、RxJava - RaxAndroid、Dagger2 和 MVP。

代码如下:

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

如您所见,我在 HomePresenter 中评论了构造函数注入。我正在那里进行现场注入。但是我无法构建项目,因为我遇到了上面提到的错误。

任何帮助将不胜感激。如果需要与代码相关的任何其他内容,请告诉我。

提前致谢。

编辑: PS:我知道答案,但我就是不明白为什么要进行现场注入,即 @Inject APIEndPoints mApiEndPoints; 在 HomePresenter 中不起作用。请有人解释一下。

【问题讨论】:

    标签: java android dependency-injection dagger-2 constructor-injection


    【解决方案1】:

    如您所见,我在 HomePresenter 中评论了构造函数注入。我正在那里进行现场注入。

    如果你使用构造函数注入,那么 Dagger 会为你创建对象 并且了解它。

    如果你使用字段注入,那么必须创建对象告诉 Dagger。

    我不明白为什么在这种情况下您更愿意使用字段注入,但是对于字段注入,您需要将 @Provides 带注释的方法添加到您的模块之一,以使 Dagger 可以访问您的演示者。

    您需要在模块中使用构造函数注入或 @Provides 注释方法,就像错误状态一样。

    【讨论】:

    • 我在 ApplicationModule 中创建了 provideAPIEndPoints() 方法。我真的很困惑何时使用字段注入以及何时使用构造函数注入。你能指导我吗?
    • @MaulikDodia 关于何时使用什么有不同的意见。我个人是构造函数注入的坚定支持者,所以你只能对 Android 框架类型使用字段注入(你不能向构造函数添加参数)我刚才写了一个 introductory blog post 如果你是有兴趣
    • 我肯定有兴趣阅读该博客。正如我在之前的评论中已经说过的,我在 ApplicationModule 中创建了 provideAPIEndPoints() 方法。那为什么我需要构造函数注入?你能详细说明你的答案吗?@DavidMedenjak
    • @MaulikDodia provideAPIEndPoints 不提供HomePresenter(请参阅您的错误)。您需要为它添加一个@Provides provideHomePresenter() 或切换回构造函数注入
    • 但是 @Inject HomePresenter homePresenter; 怎么会在 BaseActivity 中工作呢?我没有在 Module 类中为 HomePresenter 定义任何方法。@DavidMedenjak
    【解决方案2】:

    您混淆了依赖关系生产者机制和依赖关系消费机制。带注释的字段用于使用依赖项。在你的情况下,@Inject HomePresenter homePresenter 告诉 Dagger “嘿,我希望你在这里注入一个 HomePresenter”。为此,Dagger 要么需要你定义一个 @Provides 方法,要么让对象构造函数使用 @Inject 注释。

    根据经验,始终使用 @Inject 带注释的构造函数来提供依赖项。当您提供的对象是:

    • interface
    • abstract
    • 来自外部库的对象(您无权访问构造函数)
    • 在提供之前需要自定义的对象

    在您的情况下,您收到错误是因为您没有 @Provides 带注释的方法,也没有 @Inject 带注释的构造函数。您应该取消注释您的构造函数,因为它是您的情况。

    【讨论】:

    • 但是@Inject HomePresenter homePresenter; 怎么会在 BaseActivity 中工作呢?我没有在 Module class@Benjamin 中为 HomePresenter 定义任何 @Provides 方法
    • 当你用@Inject注释一个构造函数时,Dagger知道如何注入它并为你处理它(不需要@Provides方法)
    • 请仔细阅读评论。我在问你为什么 @Inject HomePresenter homePresenter; 在 BaseActivity 工作?虽然我没有注入构造函数注入。相反,我注入了归档注入,也没有在模块类中定义 @Provides 方法。这与您在上面评论中提到的相反@Benjamin
    • 上面的代码编译正确,你的HomePresenter构造函数注释了?我怀疑它
    • 正如我在问题中提到的,上面的代码给了我错误。只需回答我以下简单的问题? 1.如果我想使用字段注入,我必须在模块类中定义@Provides方法吗? 2.如果我想使用构造函数注入,@Provides就不需要了。对吗?@Benjamin
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-29
    • 2018-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多