简体   繁体   English

不能在没有 @Inject 构造函数或从 @Provides-annotated 方法的情况下提供

[英]cannot be provided without an @Inject constructor or from an @Provides-annotated method

I am using Android Dagger2 but I am getting the error below.我正在使用 Android Dagger2,但出现以下错误。

My AppModule class is:我的 AppModule 类是:

@Module
public class AppModule {
    @Provides
    public DownloadFilePresenterImp provideDownloadfilePresenterImp(DownloadFileView downloadFileView) {
        return new DownloadFilePresenterImp(downloadFileView);
    }
}

My AppComponent interface is:我的 AppComponent 接口是:

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(DownloadFileView target);
}

My DaggerInject class我的 DaggerInject 类

public class DaggerInjector {
    private static AppComponent mAppComponent = DaggerAppComponent
            .builder()
            .appModule(new AppModule())
            .build();

    public static AppComponent getAppComponent() {
        return mAppComponent;
    }
}

I am trying to inject into my Fragment (DownloadFileView)我正在尝试注入我的 Fragment (DownloadFileView)

@Inject DownloadFilePresenterImp mDownloadFilePresenterImp;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   final View view = inflater.inflate(R.layout.download_file_view, container, false);
   /* Initialize presenter */
   DaggerInjector.getAppComponent().inject(DownloadFileView.this);


   /* Use mDownloadFilePresenterImp here */       
   return view;
}

And my DownloadFilePresenterImp constructor part还有我的 DownloadFilePresenterImp 构造函数部分

public class DownloadFilePresenterImp implements DownloadFilePresenterContact {
    public DownloadFilePresenterImp(DownloadFileView downloadFileView) {
        mDownloadFileContract = downloadFileView;
    }
}

This is the error I am getting:这是我得到的错误:

Error:(17, 10) error: com.sunsystem.downloadfilechatapp.downloader.DownloadFileView cannot be provided without an @Inject constructor or from an @Provides-annotated method. This type supports members injection but cannot be implicitly provided.
com.sunsystem.downloadfilechatapp.downloader.DownloadFileView is injected at
com.sunsystem.downloadfilechatapp.downloader.dagger.AppModule.provideDownloadfilePresenterImp(downloadFileView)
com.sunsystem.downloadfilechatapp.downloader.DownloadFilePresenterImp is injected at
com.sunsystem.downloadfilechatapp.downloader.DownloadFileView.mDownloadFilePresenterImp
com.sunsystem.downloadfilechatapp.downloader.DownloadFileView is injected at
com.sunsystem.downloadfilechatapp.downloader.dagger.AppComponent.inject(target)

Many thanks for any suggestions,非常感谢您的任何建议,

The error just states that dagger doesn't have a way to provide said dependency.该错误只是指出 dagger 无法提供所述依赖项。 You will have to add it to your component in some way—and since it is a Fragment —you will have to use a @Module .你必须以某种方式将它添加到你的组件中——而且因为它是一个Fragment你将不得不使用@Module

I am assuming that your AppComponent is created by your Application on start.我假设您的AppComponent是由您的Application在启动时创建的。 Your AppComponent has a lifecycle that is longer than both your activities and fragments lifecycles are.您的AppComponent的生命周期比您的活动和片段生命周期都长。 It is therefore reasonable, that it does not know how to provide an activity, or a fragment in your case.因此,它不知道如何提供活动或在您的情况下提供片段是合理的。

  1. Your DownloadFilePresenterImp depends on your DownloadFileView .您的DownloadFilePresenterImp取决于您的DownloadFileView
  2. You want to inject DownloadFilePresenterImp into your DownloadFileView您想将DownloadFilePresenterImp注入您的DownloadFileView
  3. To inject the view and presenter you are using your AppComponent which knows nothing about the activity, and obviously nothing about the fragment.要注入视图和演示者,您正在使用您的AppComponent ,它对活动一无所知,显然对片段一无所知。 It has a different scope and lifecycle.它具有不同的范围和生命周期。

To not further cause confusion I will be talking about fragments, since their and the activities lifecycle are what you have to keep in mind.为了不再引起混乱,我将讨论片段,因为它们和活动生命周期是您必须牢记的。 You can just use DownloadFileView with the module, but those long names would get confusing.您可以将DownloadFileView与模块一起使用,但那些长名称会让人感到困惑。


To provide a fragment or activity you have to use a module.提供片段或活动,您必须使用模块。 eg例如

@Module FragmentModule {
    Fragment mFragment;
    FragmentModule(Fragment fragment) { mFragment = fragment; }

    @Provides Fragment provideFragment() { return mFragment; }

    // here you could also provide your view implementation...
    @Provides DownloadFileView provideDownloadFileView() {
        return (DownloadFileView) mFragment;
    }
}

Since this module should only live along with fragments lifecycle, you have to use either subcomponents, or components with a dependency on your AppComponent .由于此模块应该只与片段生命周期一起存在,因此您必须使用子组件或依赖于AppComponent

@Component(dependencies=AppComponent.class, modules=FragmentModule.class)
interface FragmentComponent {
    // inject your fragment
    void inject(DownloadFileView fragment);
}

In your fragment you'd have to properly create your component...在您的片段中,您必须正确创建组件...

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   final View view = inflater.inflate(R.layout.download_file_view, container, false);

   // properly create a component that knows about the fragment
   DaggerFragmentComponent.builder()
           .appComponent(DaggerInjector.getAppComponent())
           .fragmentModule(new FragmentModule(this))
           .build()
           .inject(DownloadFileView.this);

   return view;
}

Also, I highly recommend having a look at and using constructor injection另外,我强烈建议您查看并使用构造函数注入

public class DownloadFilePresenterImp implements DownloadFilePresenterContact {

    @Inject
    public DownloadFilePresenterImp(DownloadFileView downloadFileView) {
        mDownloadFileContract = downloadFileView;
    }
}

Alternatively you can move the provideDownloadfilePresenterImp(View) method to the FragmentModule to have the same effect if you like redundant code.或者,如果您喜欢冗余代码,您可以将provideDownloadfilePresenterImp(View)方法移动到FragmentModule以获得相同的效果。

Done.完成。

Ok...this should work好的...这应该工作

@Module
public class AppModule {
    @Provides
    public DownloadFilePresenterImp provideDownloadfilePresenterImp() {
        return new DownloadFilePresenterImp();
    }
}

and

public class DownloadFilePresenterImp implements DownloadFilePresenterContact {

    private WeakReference<DownloadFileView> weak;

    public DownloadFilePresenterImp() {

    }

    public void setDownloadFileView(DownloadFileView view) {
        weak = new WeakReference<>(view);
    }

    public void doSomething() {
        if (weak != null) {
            DownloadFileView view = weak.get();
            if (view != null) {
                [...]
            }
        }
    }
}

Basically, all objects provided by the graph (the component) must be built with objects belonging or built by the graph itself.基本上,图(组件)提供的所有对象都必须使用属于或由图本身构建的对象来构建。 So I removed the DownloadFilePresenterImp(DownloadFileView downloadFileView) constructor that is going to cause a leak and replaced it with a setter that creates a WeakReference to the View.因此,我删除了会导致泄漏的DownloadFilePresenterImp(DownloadFileView downloadFileView)构造函数,并将其替换为创建视图的 WeakReference 的 setter。

EDIT编辑

If you want to inject an object that you build at runtime, the only way to go is to pass that object to the AppComponent.如果要注入在运行时构建的对象,唯一的方法是将该对象传递给 AppComponent。 In your case it could be:在你的情况下,它可能是:

AppComponent.java应用组件.java

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {

    void inject(DownloadFileView target);
}

AppModule.java应用模块.java

@Module
public class AppModule {

    private final DownloadFileView downloadFileView;

    public AppModule(DownloadFileView downloadFileView) {
        this.downloadFileView = downloadFileView;
    }

    @Provides
    public DownloadFilePresenterImp provideDownloadfilePresenterImp() {
        return new DownloadFilePresenterImp(downloadFileView);
    }
}

DownloadFilePresenterImp.java下载FilePresenterImp.java

public class DownloadFilePresenterImp {

    private final DownloadFileView downloadFileView;

    public DownloadFilePresenterImp(DownloadFileView downloadFileView) {
        this.downloadFileView = downloadFileView;
    }
}

DownloadFileView.java下载FileView.java

public class DownloadFileView extends Fragment {

    private AppComponent mAppComponent;

    @Inject
    DownloadFilePresenterImp impl;


    public DownloadFileView() {
        // Required empty public constructor
        mAppComponent = DaggerAppComponent
                .builder()
                .appModule(new AppModule(this))
                .build();
        mAppComponent.inject(this);
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_download_file_view, container, false);
    }

}

In my case, I had a presenter class in Kotlin, while using Dagger2.就我而言,我在 Kotlin 中有一个演示者类,同时使用 Dagger2。 I forgot @Inject constructor as the constructor of the presenter.我忘记了@Inject constructor作为演示者的构造函数。

I highly recommend you to checkout this complete implementation of dragger : https://github.com/Spentas/securechat/blob/master/app/src/main/java/com/spentas/javad/securechat/app/AppComponent.java我强烈建议您查看此拖动器的完整实现: https : //github.com/Spentas/securechat/blob/master/app/src/main/java/com/spentas/javad/securechat/app/AppComponent.java

Or follow following:或遵循以下:

In your AppModule:在您的 AppModule 中:

@Singleton
@Provides
public DownloadFilePresenterImp  provideDownloadfilePresenterImp(DownloadFileView downloadFileView) {
    return new DownloadFilePresenterImp(downloadFileView);
}

your AppComponent:您的 AppComponent:

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
void inject(DownloadFileView target);
}

then you need to initialize your dagger in your Application Class :那么你需要在你的应用程序类中初始化你的匕首:

public class App extends Application {
private AppComponent component;

@Override
public void onCreate() {
    super.onCreate();
    mContext = this;
    component = DaggerAppComponent.builder().appModule(new AppModule(this)).build();

}
 public AppComponent getComponent(){
        return component;
    }

In wherever u want to use:在您想要使用的任何地方:

((App) App.getContext()).getComponent().inject(this);

For me the problem was that another component had an unused inject method with the same class as input parameter.对我来说,问题是另一个组件有一个未使用的注入方法,该方法与输入参数具有相同的类。 Removed that inject method and it compiled.删除了该注入方法并编译了它。

The dagger errors was not very useful匕首错误不是很有用

In my case, I was using a mismatching version between my main :app module and other modules.就我而言,我在主:app模块和其他模块之间使用了不匹配的版本。 Make sure you're using the right versions and that they are the same between modules.确保您使用正确的版本,并且模块之间的版本相同。

As a permanent fix, in my android level build.gradle , I have the following:作为永久修复,在我的 android 级别build.gradle ,我有以下内容:

buildscript {
    ext.dagger_version = "2.30.1"
}

and all my modules build.gradle files refer to the same version:并且我所有的模块build.gradle文件都引用相同的版本:

    // Dependency Injection
    implementation "com.google.dagger:dagger:$dagger_version"
    kapt "com.google.dagger:dagger-compiler:$dagger_version"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Dagger:不能在没有 @Inject 构造函数或 @Provides 注释的方法的情况下提供 - Dagger: cannot be provided without an @Inject constructor or an @Provides-annotated method 如果没有@Inject构造函数或@Provides注释的方法,则无法提供片段 - Fragment cannot be provided without an @Inject constructor or an @Provides-annotated method retrofit2.Retrofit无法在没有@Inject构造函数或@Provides注释方法的情况下提供 - retrofit2.Retrofit cannot be provided without an @Inject constructor or from an @Provides-annotated method Dagger2-没有@Inject构造函数或@Provides注释方法无法提供 - Dagger2 - cannot be provided without an @Inject constructor or from an @Provides-annotated method Dagger2:编译错误:没有@Inject构造函数或@Provides注释方法无法提供 - Dagger2: Compile error: cannot be provided without an @Inject constructor or from an @Provides-annotated method 没有@Inject构造函数或@Provides注释方法无法提供-Dagger 2 - cannot be provided without an @Inject constructor or from an @Provides-annotated method - Dagger 2 Dagger 2错误:如果没有@inject构造函数或@ provide-annotated方法,则无法提供 - Dagger 2 error: cannot be provided without an @inject constructor or from an @provides-annotated method 没有@Inject构造函数或@Provides注释方法无法提供Android Dagger 2.11 - Android Dagger 2.11 cannot be provided without an @Inject constructor or from an @Provides-annotated method Dagger2:如果没有@Inject构造函数或@ Provide-annotated方法,则无法提供 - Dagger2 : cannot be provided without an @Inject constructor or from an @Provides-annotated method okhttp3.Cache必须在没有@Inject构造函数或@Provides注释方法的情况下提供 - okhttp3.Cache cannot be provided without an @Inject constructor or from an @Provides-annotated method
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM