java Dagger2:没有绑定到片段的注入器工厂
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48872985/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dagger2: no injector factory bound for fragment
提问by C. Marr
I'm trying to convert a project that I'm building to use the dagger-android API for the DI framework, but I'm running into a dead end with an IllegalArgumentException when trying to inject a fragment using @ContributesAnroidInjector.
我正在尝试将我正在构建的项目转换为将 dagger-android API 用于 DI 框架,但是在尝试使用 @ContributesAnroidInjector 注入片段时,我遇到了 IllegalArgumentException 的死胡同。
The relevant modules and components are included below:
相关模块和组件如下:
ApplicationComponent.java
应用组件.java
@Singleton
@Component(modules = {AndroidSupportInjectionModule.class,
ApplicationModule.class,
ActivityBindingModule.class,
DataManagerModule.class})
public interface ApplicationComponent extends AndroidInjector<MyApplication> {
DataManagerContract getDataManager();
void inject(MyApplication application);
@Component.Builder
interface Builder {
@BindsInstance
ApplicationComponent.Builder application(Application application);
ApplicationComponent build();
}
}
my ActivityBindingModule.java:
我的ActivityBindingModule.java:
@Module
public abstract class ActivityBindingModule {
@ActivityScope
@ContributesAndroidInjector(modules = MainActivityModule.class)
abstract MainActivity bindMainActivity();
@ActivityScope
@ContributesAndroidInjector(modules = SplashActivityModule.class)
abstract SplashActivity bindSplashActivity();
@ActivityScope
@ContributesAndroidInjector(modules = LoginActivityModule.class)
abstract LoginActivity bindLoginActivity();
}
MainActivityModule.java
主活动模块.java
@Module
public abstract class MainActivityModule {
@ActivityScope
@Binds
abstract MainActivityContract.Presenter provideMainActivityPresenter(MainActivityPresenter presenter);
@FragmentScope
@ContributesAndroidInjector
abstract HomeFragment provideHomeFragment();
@FragmentScope
@Binds
abstract HomeFragmentContract.Presenter provideHomeFragmentPresenter(HomeFragmentPresenter presenter);
// Inject other fragments and presenters
}
SplashActivity and LoginActivity only depend on their respective presenters, and dagger works fine in these. But my MainActivity can contain numerous fragments and causes a crash when trying to inject one of those fragments using:
SplashActivity 和 LoginActivity 只依赖于它们各自的演示者,而 dagger 在这些中工作得很好。但是我的 MainActivity 可能包含大量片段并在尝试使用以下方法注入其中一个片段时导致崩溃:
HomeFragment.java
HomeFragment.java
public class HomeFragment extends Fragment {
....
@Override
public void onAttach(Context context) {
AndroidSupportInjection.inject(this);
super.onAttach(context);
}
....
}
Here is my logcat for this crash:
这是我这次崩溃的日志:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myapp/com.myapp.main.MainActivity}: java.lang.IllegalArgumentException: No injector factory bound for Class<com.myapp.ui.main.Home.HomeFragment>
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.IllegalArgumentException: No injector factory bound for Class<com.myapp.ui.main.Home.HomeFragment>
at dagger.android.DispatchingAndroidInjector.inject(DispatchingAndroidInjector.java:104)
at dagger.android.support.AndroidSupportInjection.inject(AndroidSupportInjection.java:74)
at com.myapp.ui.main.Home.HomeFragment.onAttach(HomeFragment.java:65)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1363)
at android.support.v4.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1109)
at android.support.v4.app.FragmentTransition.calculateFragments(FragmentTransition.java:996)
at android.support.v4.app.FragmentTransition.startTransitions(FragmentTransition.java:99)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2364)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229)
at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3221)
at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3171)
at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:192)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:560)
at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:177)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1248)
at android.app.Activity.performStart(Activity.java:6696)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2628)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
I'm not sure where the problem in the code is. If I move the bindings for HomeFragment to the ActivityBindingModule, the app runs fine, but the crash comes back if I bring those bindings back into the MainActivityModule. What am I doing wrong here?
我不确定代码中的问题在哪里。如果我将 HomeFragment 的绑定移动到 ActivityBindingModule,应用程序运行良好,但如果我将这些绑定带回 MainActivityModule,崩溃就会回来。我在这里做错了什么?
EDIT:
编辑:
public class MyApp extends DaggerApplication {
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerApplicationComponent.builder().application(this).build();
}
}
and my main activity:
和我的主要活动:
public class MainActivity extends AppCompatActivity
implements MainActivityContract.View,
NavigationView.OnNavigationItemSelectedListener {
@Inject
MainActivityContract.Presenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Open home fragment on first start
if (savedInstanceState == null) {
// Create new instance of HomeFragment
HomeFragment homeFragment = HomeFragment.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_main, homeFragment)
.commit();
}
// Other logic
}
回答by Benjamin
When you inject using AndroidSupportInjection.inject(this)
from your HomeFragment
, Dagger will walk the parent-fragment hierarchy to find someone that implements HasSupportFragmentInjector
. To make it work, make your MainActivity
extends DaggerAppCompatActivity
which implements HasSupportFragmentInjector
.
当您AndroidSupportInjection.inject(this)
从您的注入 using时HomeFragment
,Dagger 将遍历父片段层次结构以找到实现HasSupportFragmentInjector
. 为了让它工作,让你的MainActivity
扩展DaggerAppCompatActivity
实现HasSupportFragmentInjector
.
From the doc of AndroidSupportInjection.inject(Fragment fragment)
:
来自以下文档AndroidSupportInjection.inject(Fragment fragment)
:
Injects {@code fragment} if an associated {@link dagger.android.AndroidInjector} implementation can be found, otherwise throws an {@link IllegalArgumentException}.
Uses the following algorithm to find the appropriate {@code AndroidInjector} to use to inject {@code fragment}:
- Walks the parent-fragment hierarchy to find the a fragment that implements {@link HasSupportFragmentInjector}, and if none do
- Uses the {@code fragment}'s {@link Fragment#getActivity() activity} if it implements {@link HasSupportFragmentInjector}, and if not
- Uses the {@link android.app.Application} if it implements {@link HasSupportFragmentInjector}.
If none of them implement {@link HasSupportFragmentInjector}, a {@link IllegalArgumentException} is thrown.
@throws IllegalArgumentException if no parent fragment, activity, or application implements {@link HasSupportFragmentInjector}.
如果可以找到关联的 {@link dagger.android.AndroidInjector} 实现,则注入 {@code fragment},否则抛出 {@link IllegalArgumentException}。
使用以下算法找到合适的 {@code AndroidInjector} 用于注入 {@code fragment}:
- 遍历父片段层次结构以找到实现 {@link HasSupportFragmentInjector} 的片段,如果没有
- 使用 {@code fragment} 的 {@link Fragment#getActivity() 活动},如果它实现了 {@link HasSupportFragmentInjector},如果没有
- 如果实现了 {@link HasSupportFragmentInjector},则使用 {@link android.app.Application}。
如果它们都没有实现 {@link HasSupportFragmentInjector},则会抛出 {@link IllegalArgumentException}。
如果没有父片段、活动或应用程序实现 {@link HasSupportFragmentInjector},则@throws IllegalArgumentException。
With this, Dagger will use
有了这个,Dagger 将使用
@FragmentScope
@ContributesAndroidInjector
abstract HomeFragment provideHomeFragment();
from your MainActivityModule
to inject inside your HomeFragment
.
从您MainActivityModule
注入您的HomeFragment
.
回答by Leo Droidcoder
There could be other scenarious, where I got similar errors:
可能还有其他场景,我遇到了类似的错误:
Possible case 1:
When you have a DialogFragment
shown from a Fragment
.
It's important to use the same FragmentManager.
可能的情况 1:
当您DialogFragment
从Fragment
.
使用相同的 FragmentManager 很重要。
For instance you have a "fragment-scoped screen":
例如,您有一个“片段范围的屏幕”:
@FragmentScope
@ContributesAndroidInjector(modules = [HomeInjectors::class])
abstract fun provideHomeFragment() HomeFragment
With a subcomponent
带子组件
@Module
abstract class HomeInjectors {
@ChildFragmentScope
@ContributesAndroidInjector(modules = [DetailsModule::class])
abstract fun provideDetailsFragment(): DetailsDialogFragment
}
Important here to note, that when you show a dialog fragment, you should use child fragment managernot the Activity's one.
重要的是要注意,当您显示对话框片段时,您应该使用子片段管理器而不是活动的子片段管理器。
in this case, if you show dialog from the HomeFragment,
在这种情况下,如果您从 HomeFragment 显示对话框,
detailsDialog.show(activity.supportFragmentManager, "some tag)
and
和
detailsDialog.show(requireFragmentManager(), "some tag)
will not work.
不管用。
You should do instead:
你应该这样做:
detailsDialog.show(childFragmentManager, "some tag)
Possible case 2:Parent fragment with child fragments.
可能的情况 2:带有子片段的父片段。
In order to make child fragments with "smaller" scope (Sample code is the same as above, but consider DetailsDialogFragment a regular fragment and a child of the HomeFragment).
为了使子片段具有“较小”的范围(示例代码与上面相同,但将 DetailsDialogFragment 视为常规片段和 HomeFragment 的子片段)。
In my case, the child fragment wasn't able to find Parent's fragment injector.
就我而言,子片段无法找到父片段注入器。
The reason was that while providing a child fragment injector, I mistakenly made my BaseFragment implement HasFragmentInjector
.
However, since I use support fragments (AndroidX or whatever), I should have made BaseFragment implement HasSupportFragmentInjector
原因是在提供子片段注入器时,我错误地制作了我的BaseFragment implement HasFragmentInjector
.
但是,由于我使用支持片段(AndroidX 或其他),我应该BaseFragment implement HasSupportFragmentInjector
So the BaseFragment may look like:
所以 BaseFragment 可能看起来像:
import androidx.fragment.app.Fragment
abstract class BaseFragment : SometFragment(), HasSupportFragmentInjector {
@Inject lateinit var childFragmentInjector: DispatchingAndroidInjector<Fragment>
override fun supportFragmentInjector(): AndroidInjector<Fragment> {
return childFragmentInjector
}
override fun onAttach(context: Context) {
AndroidSupportInjection.inject(this)
super.onAttach(context)
}
}
It is useful when by certain reasons your "BaseFragment" must have other than DaggerFragment
parent
当由于某些原因你的“BaseFragment”必须有而不是DaggerFragment
父级时它很有用