卡住尝试实施官方Dagger策略以避免繁琐的代码

时间:2018-07-12 08:06:35

标签: android dependency-injection android-support-library dagger

在遵循良好的官方建议以注入和避免使用the authors themselves中繁琐的代码时,我在尝试使用支持库时遇到了麻烦。

根据文章:

  

AppCompat用户应继续实施AndroidInjector.Factory<? extends Activity> and not <? extends AppCompatActivity>(或FragmentActivity)。

我坚持使用视图总是Fragment的MVP架构,并且我不想让Activity参与任何DI业务,但是我想知道这样做是否有必要但到目前为止,我还没有做到。如果我跳过全部支持内容,则该应用程序会在运行时崩溃,因为该片段的实例是受支持的(以防万一)。然后,我进入了尝试由于编译错误而尝试进行HasSupportFragmentInjector而不是HasFragmentInjector的大量更改的任务,由于我的心理健康,我的大脑已经忘记了这些错误。一段时间后,我开始思考非支持活动如何托管支持片段。啊!那些棘手的通配符。但是,无论我如何尝试遵循建议,如果没有EmptyModule,我也无法想出一种方法,我也需要在Activity中对其进行设置,以便使用匕首和它(真的,对我而言仍然是魔术)。为什么我没有尝试过?我当然也可以,但是我对无望的改变感到厌倦,在这一点上我需要帮助。

AppModule.kt

@Singleton
@dagger.Module
class AppModule(val application: Application) {
    @Provides @Singleton fun application(): Application = application
    ...
}

AppComponent.java

@ApplicationScope
@Singleton
@Component(modules = {
        AndroidSupportInjectionModule.class,
        ...
        FooFragmentModule.class,
})
public interface AppComponent {
    Application app();
    ...
    void inject(MyApp app);
}

MyApp.java

public class MyApp extends Application implements HasActivityInjector {

    private AppComponent component;
    public AppComponent someWayToReturnAppComponent() {
        ...
    }

    @Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector;

    @Override
    public void onCreate() {
        component = DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                // more app-scoped modules
                .build();

        component.inject(this);
    }


    @Override
    public AndroidInjector<Activity> activityInjector() {
        return dispatchingActivityInjector;
    }

}

MainActivity.java

public abstract class MainActivity extends AppCompatActivity implements HasSupportFragmentInjector {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(getLayout()); // inflate the fragment via XML here
    }

    @Inject DispatchingAndroidInjector<Fragment> dispatchingFragmentInjector;

    @Override
    public AndroidInjector<Fragment> fragmentInjector() {
        return dispatchingFragmentInjector;
    }
}

FooFragmentComponent.java

@Subcomponent
public interface FooFragmentComponent extends AndroidInjector<FooFragment> {

    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<FooFragment> {}

}

FooFragmentModule.kt

@dagger.Module(subcomponents = {FooFragmentComponent.class})
public abstract class FooFragmentModule {

    @Binds
    @IntoMap
    @FragmentKey(FooFragment.class)
    abstract AndroidInjector.Factory<? extends Fragment> bindFragmentInjectorFactory(FooFragmentComponent.Builder builder);

    @ActivityScope
    abstract FooFragment contributeFooFragmentInjector();

    @Provides
    static FooPresenter presenter() {
        return new FooPresenter();
    }
}

FooFragment

public class FooFragment extends Fragment implements SomeView {

    @Inject FooPresenter presenter;

}

好。现在,回到

  

AppCompat用户应继续实施AndroidInjector.Factory<? extends Activity>

我不需要(也愿意反对)仅将其用于片段。我是否真的需要为此设置模块和组件,或者我缺少什么?

编辑

在遵循EpicPandaForce使用AndroidSupportInjectionModule的建议之后,Dagger现在抱怨

  

FragmentKey方法应该绑定dagger.android.AndroidInjector.Factory<? extends android.app.Fragment>,而不是dagger.android.AndroidInjector.Factory<? extends android.support.v4.app.Fragment>

1 个答案:

答案 0 :(得分:2)

正如注释中提到的@EpicPandaForce一样,您需要使用AndroidSupportInjectionModule来支持片段。 您还需要使用the FragmentKey in dagger.android.support,而不是the one in dagger.android这样可以使您在编辑过程中克服问题。

从广义上讲,support Fragments不要扩展base Fragments(无论如何,API 28及更高版本均已弃用)。这与AppCompatActivity及其超类the support library's FragmentActivity形成了鲜明的对比,后者都扩展了Android API级别1中引入的框架Activity。因此,无论您使用的是支持Fragments还是-在片段中,可能可能没有父AppCompatActivity,但总是具有某种Activity。这很重要,因为Android reserves the right to instantiate your Fragment using its necessary public no-arg constructor意味着Fragment只能使用在onAttach中可以找到的东西(即其父片段,其Activity或其Application)进行自我注入。

dagger.android不关心您的Activity是否为AppCompatActivity,因为除了寻找自己的注射器之外,它不使用Activity。您可以在AndroidSupportInjection.findHasFragmentInjector私有方法中看到这一点,该方法(按顺序)检查父片段的层次结构,然后是Activity,然后是Application。因此,即使实际上说支持片段只能在支持活动上正常运行,dagger.android仍可以基于超类活动绑定其键,因为没有理由区分它们并设置两个单独的映射(Activity与AppCompatActivity)。即使有这样的分隔,您也可以将AppCompatActivity注入器绑定到您的Activity映射中,所有内容都将变得非常混乱。

如果没有活动范围的绑定,则还应从该搜索顺序中选择,不需要创建活动范围的组件;您可以让您的应用程序实现HasSupportFragmentInjector,将FooFragmentModule直接安装到AppComponent中,然后从MainActivity中删除HasSupportFragmentInjector。这是非典型的,因为大多数应用程序对Activity状态或应该注入的控制器有某种感觉(甚至只是注入Activity实例本身,其上下文或资源)。如果您只是想使用@ActivityScope注释,那么您可以完全跳过该步骤,而只使用Application组件和几个Fragment子组件。但是,我认为您最终很有可能需要@ActivityScope,因此尽早为其创建一个组件是很合理的。