[英]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.因此,它不知道如何提供活动或在您的情况下提供片段是合理的。
DownloadFilePresenterImp
depends on your DownloadFileView
.DownloadFilePresenterImp
取决于您的DownloadFileView
。DownloadFilePresenterImp
into your DownloadFileView
DownloadFilePresenterImp
注入您的DownloadFileView
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.
删除了该注入方法并编译了它。
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.