关闭

Dagger2与AndroidInjector

标签: androiddagger2injector
3345人阅读 评论(1) 收藏 举报
分类:

1.遇到的问题

相信使用过Dagger开发Android应用的小伙伴会知道(如果你还不是很了解Daager,可以先看我之前的一篇基本介绍:Dagger2使用攻略),我们会在ActivityFragment的生命周期方法中执行成员注入。比如这样:

public class MyActivity extends Activity {
  @Inject 
  Test test;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    DaggerActivityComponent
                .builder()
                .appComponent(((MyApplication)this.getApplication()).getAppComponent())
                .build()
                .inject(this);
    test.getXX();
  }
}

但是有一些问题:

  1. 随着越来越多的这样代码块的复制粘贴,使得以后很难重构。

  2. 更重要的是,它要求注入类型( MyActivity )知道其注入器。 即使这是通过接口而不是具体类型完成的,它打破了依赖注入的核心原则:一个类不应该知道如何注入它。

那么我们怎么解决他呢?

2.解决问题

不用担心,Dagger2在2.10版本为我们提供了解决的方案。 并在2.11版本中增加了@ContributesAndroidInjector注解,使得我们的实现更加方便。具体变化可以查看这里

1.配置

首先将以下内容添加到您的build.gradle中:(在原先Dagger2的基础上添加)

dependencies {
  compile 'com.google.dagger:dagger-android:2.11'
  compile 'com.google.dagger:dagger-android-support:2.11'
  annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'
}

2.实现

为了更清楚的说明,我会举一个简单的例子使用新旧两种写法实现。

现在的场景是这样的,我要在一个页面中使用一个Login对象,如下:

public class Login {

    private String name ;
    private String password ;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

假设初始化name小明password******。我们使用Dagger进行依赖注入,实现UserModule

@Module
public class UserModule {

    @Provides
    Login provideXiaoMingUser() {
        Login xiaomin = new Login();
        xiaomin.setPassword("******");
        xiaomin.setName("小明");
        return xiaomin;
    }

}

相对应的UserComponent如下

@Component(modules = {UserModule.class})
public interface UserComponent {
    void inject(SecondActivity mActivity);
}

那么对应的SecondActivity也就出来了。

public class SecondActivity extends AppCompatActivity {

    @Inject
    Login xiaoming;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        DaggerUserComponent.builder()
                .userModule(new UserModule())
                .build()
                .inject(this); 

        xiaoming.getName(); //直接使用
    }

以上就是我们通常的使用方式,而SecondActivity中就体现了我们一开始说到的问题。接下来我用新方法实现一遍。

1.首先我们在AppComponent中统一注入AndroidSupportInjectionModule

@Singleton
@Component(modules = {
        AppModule.class,
        StorageModule.class,
        BuildersModule.class,
        AndroidSupportInjectionModule.class
})
interface AppComponent extends AndroidInjector<MyApplication>{

    @Component.Builder
    abstract class Builder extends AndroidInjector.Builder<MyApplication> {}

}

AndroidInjectionModule源码如下 ,AndroidSupportInjectionModule可以额外支持V4包下的Fragment.

@Beta
@Module
public abstract class AndroidInjectionModule {
  @Multibinds
  abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>
      activityInjectorFactories();

  @Multibinds
  abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>>
      fragmentInjectorFactories();

  @Multibinds
  abstract Map<Class<? extends Service>, AndroidInjector.Factory<? extends Service>>
      serviceInjectorFactories();

  @Multibinds
  abstract Map<
          Class<? extends BroadcastReceiver>, AndroidInjector.Factory<? extends BroadcastReceiver>>
      broadcastReceiverInjectorFactories();

  @Multibinds
  abstract Map<
          Class<? extends ContentProvider>, AndroidInjector.Factory<? extends ContentProvider>>
      contentProviderInjectorFactories();

  private AndroidInjectionModule() {}
}

可以看到它可以帮我们将安卓中四大组件以及Fragment进行绑定。

BuildersModule是我为了统一管理依赖于AppComponentModule添加的中间件。如下

@Module(subcomponents = {UserComponent.class})
public abstract class BuildersModule {

    @Binds
    @IntoMap
    @ActivityKey(SecondActivity.class)
    abstract AndroidInjector.Factory<? extends Activity> bindSecondActivityInjectorFactory(UserComponent.Builder builder);

}

有了BuildersModule,我们之前的UserModule保持不变,UserComponent修改如下

@Subcomponent(modules = {UserModule.class})
public interface UserComponent extends AndroidInjector<SecondActivity> {

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

}

UserComponent需继承自AndroidInjector,在该子组件中含有一个抽象类Builder,继承自AndroidInjector.Builder,并由@Subcomponent.Builder注解。注意:这里UserComponent使用@Subcomponent注解是为了使用AppComponent中的AndroidSupportInjectionModule.

接下来自定义MyApplication继承DaggerApplication

public class MyApplication extends DaggerApplication {

    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        return DaggerAppComponent.builder().create(this);
    }
}

如果我们代码中已经有继承的父类Application,则可以根据DaggerApplication源码去实现对应接口。

最后一步Activity继承DaggerAppCompatActivity,在super.onCreate(savedInstanceState)之前调用AndroidInjection.inject(this).

public class SecondActivity extends DaggerAppCompatActivity {

    @Inject
    Login xiaoming;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        xiaoming.getName(); //直接使用
    }

当然了,我们可以将AndroidInjection.inject(this)封装进BaseActivity,这样使用起来更酸爽。

有些人会觉得这写起来比之前麻烦多了,为了解决这个问题,在最近的2.11版中新增了@ContributesAndroidInjector注解。有了它我们上面的UserComponent可以不要了。(惊不惊喜,意不意外!)

@Module
public abstract class BuildersModule {

    @ContributesAndroidInjector(modules = UserModule.class)
    abstract SecondActivity secondActivityInjector();
}

我们可以看一下自动生成的代码:

@Module(subcomponents = BuildersModule_SecondActivityInjector.SecondActivitySubcomponent.class)
public abstract class BuildersModule_SecondActivityInjector {
  private BuildersModule_SecondActivityInjector() {}

  @Binds
  @IntoMap
  @ActivityKey(SecondActivity.class)
  abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(
      SecondActivitySubcomponent.Builder builder);

  @Subcomponent(modules = UserModule.class)
  public interface SecondActivitySubcomponent extends AndroidInjector<SecondActivity> {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<SecondActivity> {}
  }
}

是不是一毛一样。。。不要怪我不早说,我也是为了大家可以更多的了解其中的细节。

3.工作原理

那么它是如何工作的?(前方一大堆代码乱入,不重要部分已去除)

我们首先从MyApplication开始,在我们的父类DaggerApplication帮我们实现了注入。

public abstract class DaggerApplication extends Application{

  @Inject DispatchingAndroidInjector<Activity> activityInjector;

  @Override
  public void onCreate() {
    super.onCreate();
    injectIfNecessary();
  }

  @ForOverride
  protected abstract AndroidInjector<? extends DaggerApplication> applicationInjector();

  private void injectIfNecessary() {
    AndroidInjector<DaggerApplication> applicationInjector =
              (AndroidInjector<DaggerApplication>) applicationInjector();
          applicationInjector.inject(this); //这里注入
  }

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

注入时的具体内容

private Provider<AndroidInjector.Factory<? extends Activity>> bindAndroidInjectorFactoryProvider;

private void initialize(final Builder builder) {

    //这里不就是我们使用@ContributesAndroidInjector生成的Subcomponent吗,在这里进行了实现
    this.secondActivitySubcomponentBuilderProvider =
        new dagger.internal.Factory<
            BuildersModule_SecondActivityInjector.SecondActivitySubcomponent.Builder>() {
          @Override
          public BuildersModule_SecondActivityInjector.SecondActivitySubcomponent.Builder get() {
            return new SecondActivitySubcomponentBuilder();
          }
        };

    this.bindAndroidInjectorFactoryProvider = (Provider) secondActivitySubcomponentBuilderProvider;
    //再将所有的Activity对应的SubcomponentBuilder存进MapProviderFactory
    this.mapOfClassOfAndProviderOfFactoryOfProvider =
        MapProviderFactory
            .<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>builder(1)
            .put(SecondActivity.class, bindAndroidInjectorFactoryProvider)
            .build();

    this.dispatchingAndroidInjectorProvider =
        DispatchingAndroidInjector_Factory.create(mapOfClassOfAndProviderOfFactoryOfProvider);

    //将四大组件及Fragment全部放入
    this.myApplicationMembersInjector =
        MyApplication_MembersInjector.create(dispatchingAndroidInjectorProvider);
 }

  @Override
  public void inject(MyApplication arg0) {
    myApplicationMembersInjector.injectMembers(arg0); //注入
  }
private final class SecondActivitySubcomponentBuilder
      extends BuildersModule_ContributeSecondActivityInjector.SecondActivitySubcomponent.Builder {
    private UserModule userModule;

    private SecondActivity seedInstance;

    @Override
    public BuildersModule_ContributeSecondActivityInjector.SecondActivitySubcomponent build() {
      if (userModule == null) {
        this.userModule = new UserModule();
      }
      if (seedInstance == null) {
        throw new IllegalStateException(SecondActivity.class.getCanonicalName() + " must be set");
      }
      return new SecondActivitySubcomponentImpl(this);
    }

    @Override
    public void seedInstance(SecondActivity arg0) {
      this.seedInstance = Preconditions.checkNotNull(arg0);
    }
  }

当我们在Activity调用AndroidInjection.inject(this)时,从Application获取一个DispatchingAndroidInjector<Activity>,并将您的activity传递给inject(activity)

  public static void inject(Activity activity) {
    Application application = activity.getApplication();
    //获取DaggerApplication中的activityInjector
    AndroidInjector<Activity> activityInjector =
        ((HasActivityInjector) application).activityInjector();

    activityInjector.inject(activity);
  }

DispatchingAndroidInjector通过AndroidInjector.Factory创建AndroidInjector,并将您的activity传递至SecondActivitySubcomponentImpl中。

@Beta
public final class DispatchingAndroidInjector<T> implements AndroidInjector<T> {

  @Inject
  DispatchingAndroidInjector(
      Map<Class<? extends T>, Provider<AndroidInjector.Factory<? extends T>>> injectorFactories) {
    this.injectorFactories = injectorFactories;
  }

  @CanIgnoreReturnValue
  public boolean maybeInject(T instance) {
    Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
        injectorFactories.get(instance.getClass());
    if (factoryProvider == null) {
      return false;
    }

    @SuppressWarnings("unchecked")
    AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get();
    try {
      AndroidInjector<T> injector =
          checkNotNull(
              factory.create(instance),//<-创建
              "%s.create(I) should not return null.",
              factory.getClass().getCanonicalName());

      injector.inject(instance);//传递
      return true;
    } catch (ClassCastException e) {

    }
  }

  @Override
  public void inject(T instance) {
    boolean wasInjected = maybeInject(instance);
    if (!wasInjected) {
      throw new IllegalArgumentException(errorMessageSuggestions(instance));
    }
  }
}
private final class SecondActivitySubcomponentImpl
      implements BuildersModule_ContributeSecondActivityInjector.SecondActivitySubcomponent {
    private Provider<Login> provideXiaoMingUserProvider;

    private MembersInjector<SecondActivity> secondActivityMembersInjector;

    private SecondActivitySubcomponentImpl(SecondActivitySubcomponentBuilder builder) {
      assert builder != null;
      initialize(builder);
    }

    @SuppressWarnings("unchecked")
    private void initialize(final SecondActivitySubcomponentBuilder builder) {

      this.provideXiaoMingUserProvider =
          UserModule_ProvideXiaoMingUserFactory.create(builder.userModule);

      this.secondActivityMembersInjector =
          SecondActivity_MembersInjector.create(
              DaggerAppComponent.this.dispatchingAndroidInjectorProvider6,
              DaggerAppComponent.this.dispatchingAndroidInjectorProvider3,
              provideXiaoMingUserProvider);
    }

    @Override
    public void inject(SecondActivity arg0) {
      secondActivityMembersInjector.injectMembers(arg0);//注入
    }
  }

到此为止,它的工作流程就是这样。

细心地你其实这里会发现,我们依赖的Module不需要我们像之前一样去一个一个创建好去设置了,会默认实现它的无参构造方法。当然在这个Module中可以使用我们注入的Activity。如果你之前的Module有构造方法,试着去修改它、

4.其他

以上是以Activity作为例子实现的,对于其他的四大组件以及Fragment,使用起来大同小异。比如使用Fragment,我们就将@ActivityKey替换为@FragmentKeyAndroidInjection.inject(this)方法,在FragmentonAttach()中的super.onAttach()方法之前调用。当然如果你使用了@ContributesAndroidInjector则可以不用去管@xxxKey

@Module(subcomponents = {TestFragmentComponent.class})
public abstract class FragmentBuildersModule {

    @Binds
    @IntoMap
    @FragmentKey(TestFragment.class) //<-- 这里
    abstract AndroidInjector.Factory<? extends Fragment>
    bindTopFragmentInjectorFactory(TestFragmentComponent.Builder builder);
}

@Subcomponent(modules = TestFragmentModule.class)
public interface TestFragmentComponent extends AndroidInjector<TestFragment> {

    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<TestFragment> {

    }
}

@Module
public class TestFragmentModule {

}

public class TestFragment extends Fragment {

    @Override
    public void onAttach(Activity activity) {
        AndroidInjection.inject(this); //<--这里
        super.onAttach(activity);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment, container, false);
    }
}

我已经将这些代码上传到了我的Github,大家可以在分支dagger2.11下查看新的写法。(主分支为旧写法,方便大家对比。)

参考

  1. Dagger & Android官方文档

  2. Android and Dagger 2.10 AndroidInjector

4
0
查看评论

Dagger 2应用于Android的完美扩展库-dagger.android

Dagger 2应用于Android的完美扩展库 - dagger.android
  • IO_Field
  • IO_Field
  • 2017-05-12 15:11
  • 7002

告别Dagger2模板代码:DaggerAndroid原理解析

概述距离我的上一篇文章打破Dagger2使用窘境:Dagger-Android使用详解发布以来,有幸收获了一些朋友的认可,我很开心。在上一篇文章中,我简单叙述了Dagger2这个库目前在Android开发中的一些短板,为什么我们学习Dagger-Android这个拓展库,以及如何使用这个拓展库。今天...
  • mq2553299
  • mq2553299
  • 2017-08-30 21:35
  • 1415

告别Dagger2模板代码:Dagger Android使用详解

概述,学Dagger2-Android的理由Dagger2的窘境在使用Dagger2进行Android开发时,不可避免的问题是我们需要实例化一些Android系统的类,比如Activity或者Fragment。最理想的情况是Dagger能够创建所有需要依赖注入的对象,但事实上,我们不得不在容器的声明...
  • mq2553299
  • mq2553299
  • 2017-08-22 20:38
  • 3931

dagger2之dagger-android简单使用

dagger2的使用便利我就不用说了,google为方便android开发者进而推出了dagger-android,这里附录官方文档:[https://google.github.io/dagger/android.html] 需要增加依赖: compile 'com.google....
  • u013519084
  • u013519084
  • 2018-01-04 19:31
  • 56

Android MVVM+DataBinding结合Dagger2进行开发

前言在我的前几篇文章中,简单学习了以下内容:Android DataBinding使用总结 (一) DataBinding的环境配置和基本使用Android DataBinding使用总结(二) DataBinding的所有基本使用方法Android DataBinding使用总结(三) DataB...
  • mq2553299
  • mq2553299
  • 2017-06-05 19:52
  • 3053

Android 神兵利器Dagger2使用详解(一)基础使用

Android 神兵利器Dagger2使用详解(一)基础篇本系列书写原因:在公司一个新的共同开发项目中,使用到了Dagger2依赖注入,在使用它的时候,因为框架的原因产生了一些问题(代码风格的不同?),发现自己对于Dagger2还是有一些没有理解到位的地方,于是干脆抽个时间搞懂它,从最基础的使用开始...
  • mq2553299
  • mq2553299
  • 2017-06-11 21:56
  • 2112

Dagger2 这次入门就不用放弃了

Dagger2 这次入门就不用放弃了前言之前也研究过很多次Dagger2这东西了,可能以后RxJava+Retrofit+MVP+Dagger2是Android发展的主流框架,看了Dagger2的实现代码,有点不明所以。上网也有很多文章介绍依赖注入、Dagger2的组件等等那些,这样这样这样什么组件...
  • u012943767
  • u012943767
  • 2016-07-13 13:34
  • 21504

从Dagger2基础到Google官方架构MVP+Dagger2架构详解

博客原地址:http://www.jianshu.com/p/01d3c014b0b1 1 前言前段时间分享了一篇文章:google官方架构MVP解析与实战 ,针对这是对google官方示例架构的一个分支todo-mvp/ 的项目解析与实际运用,google官方示例架构项目googlesa...
  • u014315849
  • u014315849
  • 2016-06-02 13:12
  • 14867

Android Dagger2 MVP架构 一看就明白

Dagger2 在 MVP 架构中的使用,希望能够帮助到学习Dagger2的童鞋……
  • soslinken
  • soslinken
  • 2016-08-15 10:27
  • 11621

Android官方MVP架构解读

对于MVP (Model View Presenter)架构是从著名的MVC(Model View Controller)架构演变而来的。而对于Android应用的开发中本身可视为一种MVC架构。通常在开发中将XML文件视为MVC中的View角色,而将Activity则视为MVC中的Controll...
  • ljd2038
  • ljd2038
  • 2016-05-22 22:24
  • 40460
    个人资料
    • 访问:217330次
    • 积分:3261
    • 等级:
    • 排名:第12367名
    • 原创:70篇
    • 转载:10篇
    • 译文:0篇
    • 评论:228条
    多多支持
    博客专栏
    最新评论