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;
}
}
フラグメント(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)
提案に感謝します、
わかりました...これは動作するはずです
_@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)
コンストラクターを削除し、ビューへのWeakReferenceを作成するセッターに置き換えました。
[〜#〜] edit [〜#〜]
実行時にビルドするオブジェクトを注入する場合、実行する唯一の方法は、そのオブジェクトを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);
}
}
_
このエラーは、短剣には前述の依存関係を提供する方法がないことを示しています。何らかの方法でコンポーネントに追加する必要があります。Fragment
なので、_@Module
_を使用する必要があります。
AppComponent
は、起動時にApplication
によって作成されると想定しています。 AppComponent
のライフサイクルは、アクティビティとフラグメントのライフサイクルよりも長いです。したがって、アクティビティまたはフラグメントを提供する方法がわからない場合は合理的です。
DownloadFilePresenterImp
はDownloadFileView
に依存します。DownloadFilePresenterImp
をDownloadFileView
に注入したいAppComponent
を使用しています。スコープとライフサイクルが異なります。さらに混乱を引き起こさないために、フラグメントとアクティビティのライフサイクルがあなたが心に留めておくべきものなので、フラグメントについて話します。モジュールではDownloadFileView
を使用できますが、これらの長い名前は混乱を招きます。
モジュールを使用するhaveがあるフラグメントまたはアクティビティをprovideする例えば.
_@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;
}
}
_
このモジュールはフラグメントのライフサイクルとともにのみ有効であるため、haveを使用して、サブコンポーネントまたは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;
}
_
また、私は強く推奨を見て、使用してconstructor injection
_public class DownloadFilePresenterImp implements DownloadFilePresenterContact {
@Inject
public DownloadFilePresenterImp(DownloadFileView downloadFileView) {
mDownloadFileContract = downloadFileView;
}
}
_
別の方法として、provideDownloadfilePresenterImp(View)
メソッドをFragmentModule
に移動して、冗長コードが必要な場合に同じ効果を得ることができます。
できた.
私にとっての問題は、別のコンポーネントに、入力パラメーターと同じクラスの未使用の注入メソッドがあることでした。その注入メソッドを削除し、コンパイルしました。
私の場合、Dagger2を使用しながら、Kotlinにプレゼンタークラスがありました。忘れてた @Inject constructor
プレゼンターのコンストラクターとして。
ドラッガーのこの完全な実装をチェックアウトすることを強くお勧めします: 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);