如果没有@Inject构造函数或@ Provide-annotated方法,则无法提供

ant*_*009 27 android dagger-2

我正在使用Android Dagger2,但我收到以下错误.

我的AppModule类是:

@Module
public class AppModule {
    @Provides
    public DownloadFilePresenterImp provideDownloadfilePresenterImp(DownloadFileView downloadFileView) {
        return new DownloadFilePresenterImp(downloadFileView);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的AppComponent接口是:

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

我的DaggerInject类

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

    public static AppComponent getAppComponent() {
        return mAppComponent;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想注入我的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;
}
Run Code Online (Sandbox Code Playgroud)

和我的DownloadFilePresenterImp构造函数部分

public class DownloadFilePresenterImp implements DownloadFilePresenterContact {
    public DownloadFilePresenterImp(DownloadFileView downloadFileView) {
        mDownloadFileContract = downloadFileView;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误:

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)
Run Code Online (Sandbox Code Playgroud)

非常感谢任何建议,

Dav*_*jak 27

该错误只表明dagger无法提供所述依赖关系.您必须以某种方式将它添加到您的组件 - 因为它是Fragment- 您将不得不使用@Module.

我假设你AppComponent是由你Application的开始创建的.您AppComponent的生命周期比您的活动和片段生命周期都长.因此,它是合理的,它不知道如何在您的案例中提供活动或片段.

  1. 你的DownloadFilePresenterImp意志取决于你DownloadFileView.
  2. 你想注入DownloadFilePresenterImp你的DownloadFileView
  3. 要注入视图和演示者,您使用的AppComponent是对活动一无所知的内容,显然没有关于片段的内容.它具有不同的范围和生命周期.

为了不进一步引起混淆,我将讨论片段,因为它们和活动生命周期是你必须记住的.你可以使用DownloadFileView模块,但那些长名称会让人感到困惑.


提供片段或活动,您必须使用模块.例如

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

由于此模块应仅与片段生命周期一起使用,因此必须使用子组件或具有依赖关系的组件AppComponent.

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

在您的片段中,您必须正确创建组件...

@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;
}
Run Code Online (Sandbox Code Playgroud)

另外,我强烈建议您查看并使用构造函数注入

public class DownloadFilePresenterImp implements DownloadFilePresenterContact {

    @Inject
    public DownloadFilePresenterImp(DownloadFileView downloadFileView) {
        mDownloadFileContract = downloadFileView;
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您喜欢冗余代码,则可以将provideDownloadfilePresenterImp(View)方法移动FragmentModule到具有相同效果的方法.

完成.


Sav*_* B. 6

就我而言,我在 Kotlin 中有一个演示者类,同时使用 Dagger2。我忘了 @Inject constructor 作为演示者的构造函数。


Mim*_*oli 5

好...这应该工作

@Module
public class AppModule {
    @Provides
    public DownloadFilePresenterImp provideDownloadfilePresenterImp() {
        return new DownloadFilePresenterImp();
    }
}
Run Code Online (Sandbox Code Playgroud)

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) {
                [...]
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上,图(组件)提供的所有对象都必须使用图本身所属或构建的对象来构建。因此,我删除了DownloadFilePresenterImp(DownloadFileView downloadFileView)会导致泄漏的构造函数,并用创建对视图的WeakReference的setter进行了替换。

编辑

如果要注入在运行时生成的对象,唯一的方法是将该对象传递给AppComponent。在您的情况下,可能是:

AppComponent.java

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

    void inject(DownloadFileView target);
}
Run Code Online (Sandbox Code Playgroud)

AppModule.java

@Module
public class AppModule {

    private final DownloadFileView downloadFileView;

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

    @Provides
    public DownloadFilePresenterImp provideDownloadfilePresenterImp() {
        return new DownloadFilePresenterImp(downloadFileView);
    }
}
Run Code Online (Sandbox Code Playgroud)

下载FilePresenterImp.java

public class DownloadFilePresenterImp {

    private final DownloadFileView downloadFileView;

    public DownloadFilePresenterImp(DownloadFileView downloadFileView) {
        this.downloadFileView = downloadFileView;
    }
}
Run Code Online (Sandbox Code Playgroud)

下载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);
    }

}
Run Code Online (Sandbox Code Playgroud)