Dagger2:片段

时间:2018-02-19 19:32:56

标签: java android dagger-2

我正在尝试将我正在构建的项目转换为使用dagger-android API用于DI框架,但是当尝试使用@ContributesAnroidInjector注入片段时,我遇到了IllegalArgumentException的死胡同。

相关模块和组件包含在下面:

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

我的 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

@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和LoginActivity仅取决于他们各自的演示者,并且匕首在这些方面工作得很好。但是我的MainActivity可能包含大量碎片,并在尝试使用以下方法注入其中一个碎片时导致崩溃:

HomeFragment.java

public class HomeFragment extends Fragment {
    ....
    @Override
    public void onAttach(Context context) {
        AndroidSupportInjection.inject(this);
        super.onAttach(context);
    }
    ....
}

这是我崩溃的logcat:

                                                                    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) 

我不确定代码中的问题在哪里。如果我将HomeFragment的绑定移动到ActivityBindingModule,应用程序运行正常,但如果我将这些绑定带回MainActivityModule,则会发生崩溃。我在这里做错了什么?

修改

public class MyApp extends DaggerApplication {

    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        return DaggerApplicationComponent.builder().application(this).build();
    }
}

和我的主要活动:

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
}

3 个答案:

答案 0 :(得分:12)

当您使用AndroidSupportInjection.inject(this)中的HomeFragment进行注入时,Dagger将遍历父片段层次结构以找到实现HasSupportFragmentInjector的人。要使其有效,请使用MainActivity扩展DaggerAppCompatActivity来实现HasSupportFragmentInjector

来自AndroidSupportInjection.inject(Fragment fragment)的文件:

  

如果关联{@link,则注入{@code fragment}   可以找到dagger.android.AndroidInjector}实现,否则   抛出{@link IllegalArgumentException}。

     

使用以下算法查找相应的{@code   AndroidInjector}用于注入{@code fragment}:

     
          
  1. 使用父片段层次结构查找实现{@link的片段       HasSupportFragmentInjector},如果没有的话       
  2. 如果它实现了{@code fragment}的{@link Fragment#getActivity()activity}       {@link HasSupportFragmentInjector},如果没有       
  3. 如果它实现{@link,则使用{@link android.app.Application}       HasSupportFragmentInjector}。
     

如果他们都没有实现{@link HasSupportFragmentInjector},那么{@link   抛出IllegalArgumentException}。

     

@throws IllegalArgumentException如果没有父片段,活动或   应用程序       {@link HasSupportFragmentInjector}。

有了这个,Dagger将使用

@FragmentScope
@ContributesAndroidInjector
abstract HomeFragment provideHomeFragment();

从你的MainActivityModule注入HomeFragment

答案 1 :(得分:0)

这种情况可能发生的另一种情况是,您在DialogFragment中显示了Fragment
使用相同的FragmentManager很重要。

例如,您有一个“片段范围屏幕”:

@FragmentScope
@ContributesAndroidInjector(modules = [DetailsInjectors::class])
abstract fun provideHomeFragment() HomeFragment

带有子组件

@Module
abstract class DetailsInjectors {

    @ChildFragmentScope
    @ContributesAndroidInjector(modules = [DetailsModule::class])
    abstract fun provideDetailsFragment(): DetailsDialogFragment

}

这里要注意的重要一点是,当您显示对话框片段时, 您应该使用子片段管理器,而不是活动的。

在这种情况下,如果您从HomeFragment显示对话框,

detailsDialog.show(activity.supportFragmentManager, "some tag)

detailsDialog.show(requireFragmentManager(), "some tag)

不起作用。

您应该改为:

detailsDialog.show(childFragmentManager, "some tag)

答案 2 :(得分:0)

就我而言,我没有在@ Fragment类中定义Module!所以当我像这样添加它时:

@ActivityScope
@ContributesAndroidInjector(modules = {ActivityModule.class})
abstract InvestmentDetailsFragment bindInvestmentDetailsFragment();

我的问题已解决!