美文网首页
Android和Dagger 2.10 AndroidInjec

Android和Dagger 2.10 AndroidInjec

作者: 大于于 | 来源:发表于2017-08-30 18:11 被阅读483次

    Android上常见的Dagger设置通常涉及Application Component和Application Module,其中前者用于注入组件(例如Activity,Fragment等)。

    @Component(modules = { AppModule.class })
    public interface AppComponent {
        @Component.Builder
        interface Builder {
            @BindsInstance Builder application(App application);
            AppComponent build();
        }    
        void inject(FeatureActivity featureActivity);
    }
    
    @Module
    public class AppModule {
        @Provides Context provideContext(App application) {
            return application.getApplicationContext();
        }
        @Singleton @Provides SomeClientApi provideSomeClientApi() {
            return new SomeClientApiImpl();
        }
    }
    
    public class App extends Application {
        private AppComponent appComponent;
        @Override
        public void onCreate() {
            super.onCreate();
            appComponent = DaggerAppComponent
                .builder()
                .application(this)
                .build();
        }
        public AppComponent getAppComponent() {
            return appComponent;
        }
    }
    

    由于Android框架为我们实例化了这些组件,所以我们必须执行成员注入,使用@Inject 注释包可见的类字段,如下所示:

    public class FeatureActivity extends AppCompatActivity {
      @Inject SomeClientApi mSomeClientApi; 
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ((App)getApplication())
            .getAppComponent()
            .inject(this);
      }
    }
    

    然而,这种模式打破了依赖注入的核心原则:一个类不应该知道它是如何注入的。新推出的dagger-android模块专门解决了这个问题 - 将注入的类与注入器分离。使用新的dagger-android模块,首先,将以下Gradle依赖项添加到build.gradle中:

    // Dagger core dependencies
    annotationProcessor 'com.google.dagger:dagger-compiler:2.10'
    compile 'com.google.dagger:dagger:2.10'
    // Dagger Android dependencies
    annotationProcessor 'com.google.dagger:dagger-android-processor:2.10'
    compile 'com.google.dagger:dagger-android:2.10'
    // Use this instead if you're using support library
    compile 'com.google.dagger:dagger-android-support:2.10'
    

    如果您从旧版本的Dagger进行升级,请确保将版本(2.10)设置为所有与匕首相关的依赖关系。另外值得一提的是,我在本教程中使用Android Gradle插件2.3.0。如果您使用的版本比2.2.0老,你要替换annotationProcessor用apt。在我们的项目中,新模块的设置不仅仅需要一个组件和一个模块。我的建议是具有以下类结构:

    /
    | App (extending Application)
    | AppComponent
    | AppModule
    | BuildersModule

    • feature/
      | FeatureModule
      | FeatureSubComponent

    我们可以看到,在上面的典型设置之上,我们还添加了3个类(BuildersModule,FeatureModule,FeatureSubComponent)。每个功能都有自己的sub component和module。

    我使用术语“ Feature”来描述应用程序中的一个屏幕(或Activity)。

    1.subcomponent必须继承AndroidInjector<TheActivity>并具有继承AndroidInjector.Builder<TheActivity>的抽象类

    @Subcomponent
    public interface FeatureSubComponent extends AndroidInjector<FeatureActivity> {
        @Subcomponent.Builder
        abstract class Builder extends AndroidInjector.Builder<FeatureActivity> {
        }
    }
    

    2.然后,我们需要在BuildersModule中添加绑定到sub component的Builder中,以便Dagger能够注入FeatureActivity。后期的 sub components builders的绑定也需要添加到此类中。

    @Module
    public abstract class BuildersModule {
        @Binds
        @IntoMap
        @ActivityKey(FeatureActivity.class)
        abstract AndroidInjector.Factory<? extends Activity> bindFeatureActivityInjectorFactory(FeatureActivitySubComponent.Builder builder);
    // Add more bindings here for other sub components
    }
    

    在此为其他子组件添加更多绑定

    3.接下来,我们需要连接FeatureSubComponent,AppModule通过在@Module注解里面指定subcomponents

    @Module(subcomponents = { FeatureSubComponent.class })
    public class AppModule {
        @Provides Context provideContext(App application) {
            return application.getApplicationContext();
        }
        @Singleton @Provides SomeClientApi provideSomeClientApi() {
            return new SomeClientApiImpl();
        }
    }
    

    4.和电线
    BuildersModule到AppComponent:

    @Component(modules = {
            /* Use AndroidInjectionModule.class if you're not using support library */
            AndroidSupportInjectionModule.class,
            AppModule.class,
            BuildersModule.class })
    public interface AppComponent {
        @Component.Builder
        interface Builder {
            @BindsInstance Builder application(App application);
            AppComponent build();
        }
        void inject(App app);
    }
    

    请注意AppComponent:除了添加BuildersModule的@Component(modules= {…}),我们还增加了AndroidSupportInjectionModule,这是一个内置的模块匕首,机器人必须安装在AppComponent按照该规定的官方文档,这是必要的,以确保所有绑定必要对这些基站类型可用。
    我们删除了inject()方法,FeatureActivity并用inject()我们的App类的方法替换了它。

    5.然后,我们修改我们的App类,以便它实现HasDispatchingActivityInjector和@Inject一个DispatchingAndroidInjector<Activity>从返回activityInjector()的方法。在onCreate(),我们建立AppComponent并且调用inject(this)。

    public class App extends Application implements HasDispatchingActivityInjector {
        @Inject DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
    
        @Override
        public void onCreate() {
            super.onCreate();
            DaggerAppComponent
                    .builder()
                    .application(this)
                    .build()
                    .inject(this);
        }
    
        @Override
        public DispatchingAndroidInjector<Activity> activityInjector() {
            return dispatchingAndroidInjector;
        }
    }
    

    请注意,在Dagger 2.11版中,所有HasDispatchingInjector的界面都已被重命名为HasInjectors
    最后,FeatureActivity我们删除了我们在那里注入活动的代码,而我们在调用之前调用,因为调用超级在配置更改期间附加上一个活动实例的Fragments,而后者又会注入Fragments。为了使Fragment注入成功,必须注意Activity:AndroidInjection.inject(this) super.onCreate()

    public class FeatureActivity extends AppCompatActivity implements FeatureView {
       @Inject SomeClientApi mSomeClientApi;
       @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            AndroidInjection.inject(this);
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    }
    

    向Activity自己的组件注入自定义参数
    在某些情况下,您需要注入活动本身提供的参数。之前完成的常见方法是在调用inject()活动的组件之前将参数传递给模块的构造函数。例如,如果我们按照这里描述的MVP设计模式,我们的Presenter将把View作为构造函数参数的一部分。这意味着我们需要将该活动作为参数传递给模块构造函数。在匕首android之前,这样做是这样做的:

    @Module
    class FeatureModule {
        private FeatureView view;
    
        public FeatureModule(FeatureView view) {
            this.view = view;
        }
    
        @Provides FeatureView provideView() {
            return view;
        }
    }
    

    在演示者中,我们将使用构造函数注入:

    class FeaturePresenter {
        private final FeatureView view;
        
        @Inject
        Presenter(FeatureView view) {
            this.view = view;    
        }
        public void doSomething() {
        }
    }
    

    最后,构建组件,传递一个新的模块实例并注入该活动:

    public class FeatureActivity extends AppCompatActivity implements FeatureView {
        @Inject FeaturePresenter presenter;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerFeatureComponent.builder()
                    .featureModule(FeatureModule(this)).build()
                    .inject(this)
            
            // presenter ready to be used
            presenter.doNothing();
        }
    }
    

    但是我们如何用新的匕首 - Android模块呢?毕竟,我们在活动中只有一个调用 -  没有办法像以前那样传递一个新的模块实例。
    AndroidInjection.inject(this)

    答案是,我们不再需要这样做了。使用dagger-android模块,该活动已经是图表的一部分。那实际上是什么意思呢?这意味着我们所有的都创建一个绑定,将在任何FeatureView请求的地方注入活动。这样做的方法是使用Dagger的@Binds注释。为此,我们将创建一个新的模块类FeatureModule,它将包含所有特性绑定。

    @Module
    public abstract class FeatureModule {
        @Binds
        abstract FeatureView provideFeatureView(FeatureActivity featureActivity);
        }
    }
    

    这是伟大的,但你可能想知道,如果我想传递除活动之外的其他参数呢?假设您有一个唯一的ID,通过活动的附加功能传递给活动,演示者需要它。例如,假设演示者需要此ID才能发出HTTP请求。执行此操作的方法是使用带有@Named注释的限定符。所以我们的主持人会像这样:

    class FeaturePresenter {
        private FeatureView featureView;
        private String someId;
    
        @Inject
        public FeaturePresenter(FeatureView featureView, @Named("someId") String someId) {
            this.featureView = featureView;
            this.someId = someId;
        }
    
        public void doNothing() {
            featureView.doNothing();
        }
    }
    

    现在我们已经看到,通过AndroidInjection.inject(this)调用注入活动是不可能传递参数的。那么我们如何使图形知道这个ID?这有点棘手,可能实际上是一个黑客,但目前一种方法是将ID保存在活动中的一个字段中,然后FeatureModule提供它。

    1.首先我们将ID保存在一个字段中 FeatureActivity

    public class FeatureActivity extends AppCompatActivity implements FeatureView {
        @Inject FeaturePresenter presenter;
    
        String someId;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            someId = getIntent().getStringExtra(EXTRA_SOME_ID);
            AndroidInjection.inject(this);
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            presenter.doNothing();
        }
    
        @Override
        public void doNothing() {
    
        }
    }
    

    然后我们添加一个提供方法 FeatureModule

    @Module
    public abstract class FeatureModule {
        @Binds
        abstract FeatureView provideFeatureView(FeatureActivity featureActivity);
    
        @Provides @Named("someId") static String provideSomeId(FeatureActivity featureActivity) {
            return featureActivity.someId;
        }
    }
    

    如前所述,这是可能的,因为FeatureActivity已经在图中。

    注入活动以外
    如本教程开头所述,Fragment注入以及其他Android组件不在本教程的范围之内。在官方文件涵盖了片段下喷吹片段的对象,我强烈建议你阅读它。还有更多关于服务和接收器的信息。

    结论
    新的dagger-android模块正在使我们更接近于适当的依赖注入,尽管在我看来,它比以前更复杂。
    匕首团队正在积极致力于进一步简化,我不用怀疑API将尽快进行其他更改。
    在撰写本教程之前,还没有提供官方样品。
    您可能想要查看

    原文链接
    [https://android.jlelse.eu/android-and-dagger-2-10-androidinjector-5e9c523679a3]

    相关文章

      网友评论

          本文标题:Android和Dagger 2.10 AndroidInjec

          本文链接:https://www.haomeiwen.com/subject/spsxjxtx.html