Dagger2与AndroidInjector

Dagger2与AndroidInjector使用过 Dagger 开发 Android 应用的小伙伴会知道我们会在 Activity 或 Fragment 的生命周期方法中执行成员注入 比如这样

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 
   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 
  
    activityInjector; 
   @Override 
   public 
   void 
   onCreate() { 
   super.onCreate(); injectIfNecessary(); } 
   @ForOverride 
   protected 
   abstract AndroidInjector 
    
   applicationInjector(); 
   private 
   void 
   injectIfNecessary() { AndroidInjector 
   
     applicationInjector = (AndroidInjector 
    
      ) applicationInjector(); applicationInjector.inject( 
     this); 
     //这里注入 } 
     @Override 
     public DispatchingAndroidInjector 
      
      activityInjector() { 
      return activityInjector; } } 
      
     
    
  

注入时的具体内容

private Provider 
      
       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传递给inject(activity)

 public static void inject(Activity activity) { Application application = activity.getApplication(); //获取DaggerApplication中的activityInjector AndroidInjector 
  
    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 
   
    extends T>> factoryProvider = injectorFactories.get(instance.getClass()); 
   if (factoryProvider == 
   null) { 
   return 
   false; } @SuppressWarnings( 
   "unchecked") AndroidInjector.Factory 
   
     factory = (AndroidInjector.Factory 
    
      ) factoryProvider.get(); 
     try { AndroidInjector 
     
       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 
  
    provideXiaoMingUserProvider; 
   private MembersInjector 
   
     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 
   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
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/209851.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午8:19
下一篇 2026年3月19日 上午8:20


相关推荐

  • ios -特殊符号大全分享给大家,直接复制粘贴就可以使用了!

    ios -特殊符号大全分享给大家,直接复制粘贴就可以使用了!░▒▬♦◊◦♠♣▣۰•●❤●•۰►◄▧▨♨◐◑↔↕▪▫☼♦♧♡♂♀♠♣♥❤☜☞☎☏⊙◎☺☻☼▧▨♨◐◑↔↕▪▒◊◦▣▤▥▦▩◘◈◇♬♪♩♭♪の★☆→あぃ£Ю〓§♤♥▶¤๑⊹⊱⋛⋌⋚⊰⊹≈๑۩۩….۩۩๑๑۩۞۩๑✲❈✿✲❈➹~.~◕‿-。☀☂☁【】┱┲❣✚✪✣✤✥✦❉❥❦❧❃❂❁…

    2022年5月5日
    100
  • 图析:String,StringBuffer与StringBuilder的区别

    图析:String,StringBuffer与StringBuilder的区别一、JavaString类——String字符串常量字符串广泛应用在Java编程中,在Java中字符串属于对象,Java提供了String类来创建和操作字符串。需要注意的是,String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,这样不仅效率低下,而且大量浪费有限的内存空间。我们来看一下这张对String操作时内存变化的图:我们可…

    2022年6月28日
    34
  • JavaScript触屏滑动API介绍

    随着触屏手机、平板电脑的普及和占有更多用户和使用时间,触屏的触碰、滑动等事件也成为javaScript开发不可避免的知识,现在何问起就和大家一起学习js的触屏操作,js的触屏touchmove事件,为

    2021年12月28日
    44
  • 2021goland激活码 3月最新注册码

    2021goland激活码 3月最新注册码,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月15日
    54
  • 线程池源码分析_executors源码解析

    线程池源码分析_executors源码解析概述在java中,线程池ThreadPoolExecutor是一个绕不过去的类,它是享元模式思想的体现,通过在容器中创建一定数量的线程加以重复利用,从而避免频繁创建线程带来的额外开销。一个设

    2022年8月16日
    30
  • 可视化数据库设计软件有哪些_数据库可视化编程

    可视化数据库设计软件有哪些_数据库可视化编程学习目标:C#数据库应用程序的开发环境的构成服务器资源管理器类型化数据集创建简单的数据库应用程序水晶报表Notes:类型化数据集利用服务器资源管理器建立数据连接利用服务器资源管理器可执行的任务如下:1)打开数据连接。2)登录到服务器上,并显示服务器的数据库和系统服务,包括事件日志、消息队列、性能计数器、系统服务和SQL数据库。3)查看关于可用Web服务的信息以及使信息…

    2022年4月20日
    56

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号