Android和Dagger 2.10 AndroidInjector

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并具有继承AndroidInjector.Builder的抽象类

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

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

@Module
public abstract class BuildersModule {
    @Binds
    @IntoMap
    @ActivityKey(FeatureActivity.class)
    abstract AndroidInjector.Factory 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从返回activityInjector()的方法。在onCreate(),我们建立AppComponent并且调用inject(this)。

public class App extends Application implements HasDispatchingActivityInjector {
    @Inject DispatchingAndroidInjector dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        DaggerAppComponent
                .builder()
                .application(this)
                .build()
                .inject(this);
    }

    @Override
    public DispatchingAndroidInjector 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 AndroidInjector)