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

时间:2016-05-25 10:39:45

标签: android dagger-2

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

我的AppModule类是:

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

我的AppComponent界面是:

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

我的DaggerInject类

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

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

我正在尝试注入我的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;
}

我的DownloadFilePresenterImp构造函数部分

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

这是我得到的错误:

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)

非常感谢任何建议,

6 个答案:

答案 0 :(得分:24)

错误只表明dagger没有办法提供所述依赖关系。您必须以某种方式将其添加到您的组件中 - 因为它是Fragment - 您必须使用@Module

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

  1. 您的DownloadFilePresenterImp取决于您的DownloadFileView
  2. 您想将DownloadFilePresenterImp注入DownloadFileView
  3. 要注入视图和演示者,您正在使用对此活动一无所知的AppComponent,而且显然没有关于该片段的信息。它有不同的范围和生命周期。
  4. 为了不进一步引起混淆,我将讨论片段,因为它们和活动生命周期是你必须记住的。你可以在模块中使用DownloadFileView,但这些长名称会让人感到困惑。

    提供 使用模块的片段或活动。 e.g。

    @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;
        }
    }
    

    由于此模块应仅与片段生命周期一起使用,因此 可以使用子组件或与AppComponent具有相关性的组件。

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

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

    @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;
    }
    

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

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

    或者,如果您喜欢冗余代码,可以将provideDownloadfilePresenterImp(View)方法移至FragmentModule以获得相同的效果。

    完成。

答案 1 :(得分:4)

好的......这应该有效

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

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) {
                [...]
            }
        }
    }
}

基本上,图形(组件)提供的所有对象必须使用属于或由图形本身构建的对象构建。所以我删除了导致泄漏的DownloadFilePresenterImp(DownloadFileView downloadFileView)构造函数,并将其替换为为View创建WeakReference的setter。

修改

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

AppComponent.java

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

    void inject(DownloadFileView target);
}

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

DownloadFilePresenterImp.java

public class DownloadFilePresenterImp {

    private final DownloadFileView downloadFileView;

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

DownloadFileView.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);
    }

}

答案 2 :(得分:2)

对我来说问题是另一个组件有一个未使用的inject方法,它与输入参数具有相同的类。删除了那个注入方法,然后编译。

答案 3 :(得分:2)

就我而言,我在使用Dagger2时在Kotlin中有一个演讲者班。我忘了 def change(array,array2): array = "heyo" array2 = "7" return array,array2 def main(): array, array2 = change(array,array2) print(array,array2) if __name__ == '__main__': main() 作为演示者的构造函数。

答案 4 :(得分:1)

我强烈建议您查看这个完整的dragger实现: https://github.com/Spentas/securechat/blob/master/app/src/main/java/com/spentas/javad/securechat/app/AppComponent.java

或者按照以下步骤操作:

在你的AppModule中:

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

您的AppComponent:

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

然后你需要在你的应用程序类中初始化你的匕首:

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

无论你想在哪里使用:

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

答案 5 :(得分:1)

匕首错误不是很有用

就我而言,我在主 :app 模块和其他模块之间使用了不匹配的版本。确保您使用正确的版本,并且模块之间的版本相同。

作为永久性修复,在我的 android 级别 build.gradle 中,我有以下内容:

buildscript {
    ext.dagger_version = "2.30.1"
}

并且我所有的模块 build.gradle 文件都指向相同的版本:

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