Dagger2使用详解

Dagger2使用详解Dagger2 是目前流行的一个依赖注入框架 使用它可以降低我们程序中类与类之间的耦合 类实例的创建 初始化 销毁及相互依赖都交由 dagger2 来管理 我们只需要专注于类本身的业务逻辑 提高我们编写程序的便利性 传统 MVP 案例 MVP 是我们项目中经常使用的一个应用框架 Model 层负责具体的业务逻辑 View 层负责界面的展示 Presenter 层负责协调 Model 层与 View 层 通过调用 Model 层的业

Dagger2是目前流行的一个依赖注入框架。使用它可以降低我们程序中类与类之间的耦合。类实例的创建,初始化,销毁及相互依赖都交由dagger2来管理。我们只需要专注于类本身的业务逻辑,提高我们编写程序的便利性。

传统MVP案例

MVP是我们项目中经常使用的一个应用框架。Model层负责具体的业务逻辑,View层负责界面的展示,Presenter层负责协调Model层与View层,通过调用Model层的业务方法,更新View层的界面展示。现在假如我们由这样一个需求:要求我们获取一段信息在界面上展示。应用MVP框架,我们可以这样实现:

/ * 定义一个View层的统一接口 */ public interface IView { 
    void updateUI(String text); } / * View层,负责界面的展示 */ public class TestActivity extends AppCompatActivity implements IView { 
    TestPresent mPresent;//Present层实例 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); mPresent=new TestPresent(this);//创建Present层的实例 mPresent.updateUI();//调用Present层的更新UI的方法 } @Override public void updateUI(String text) { ((TextView)findViewById(R.id.textview)).setText(text); } } / * Present类,调用Model层的业务方法,更新View层的界面展示 */ public class TestPresent { 
    IView mView;//View层实例 TestModel mModel;//Model层实例 //构造方法,传入View层的实例 public TestPresent(IView view){ this.mView=view; this.mModel=new TestModel();//创建Model层的实例 } //更新UI的方法 public void updateUI(){ mView.updateUI(mModel.getText());//调用Model层是业务逻辑,更新View层的界面展示 } } / * Model类,实现具体的业务逻辑 */ public class TestModel { 
    public TestModel(){ } //返回需要展示的信息 public String getText(){ return "Dagger2应用实践..."; } }

通过以上代码,我们顺利的通过MVP框架实现了我们的需求,代码模块间分工明确,各模块只负责自己本模块的工作。但是这里有一个问题,模块之间相互依赖,一个模块都要依赖其它的模块才能完成实际的功能。根据单一职责原则,一个内聚性高的类,应该只做自己类本身的工作,在需要使用其它的类时,我们只要调用类实例的方法就可以了,实例的创建,初始化,销毁等工作,则不应该由本类负责。通过依赖注入框架,我们就可以只关注类本身的工作,依赖类的创建,初始化,销毁等工作,统统交给依赖注入框架来处理。

Dagger2案例

Dagger2是通过apt根据注解在编译时生成额外的代码实现依赖注入,所以要使用dagger2,首先我们需要在build.gradle(Project:xxx)中配置apt插件:

dependencies { classpath 'com.android.tools.build:gradle:2.3.3' //添加apt插件 classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' }

在build.gradle(Module:app)中添加添加dagger2依赖:

apply plugin: 'com.android.application' //添加如下代码,应用apt插件 apply plugin: 'com.neenbedankt.android-apt' ... dependencies { ... //dagger2 compile 'com.google.dagger:dagger:2.4' apt 'com.google.dagger:dagger-compiler:2.4' //java注解 compile 'org.glassfish:javax.annotation:10.0-b28' }

使用Dagger2注解修改各个类:

/ * 定义一个View层的统一接口 * View接口保持不变 */ public interface IView { 
    void updateUI(String text); } / * View层,负责界面的展示 */ public class TestActivity extends AppCompatActivity implements IView{ 
    //当一个成员变量被@Inject注解修饰,并且它的类型构造函数也被@Inject注解修饰,dagger2就会自动实例化该成员类型,并注入到该成员变量 @Inject TestPresent mPresent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); DaggerTestComponent.builder().testModule(new TestModule(this)).build().inject(this);//@Component负责连接起@Inject和@Module注解 mPresent.updateUI(); } @Override public void updateUI(String text) { ((TextView)findViewById(R.id.textview)).setText(text); } } / * Present类,调用Model层的业务方法,更新View层的界面展示 */ public class TestPresent { 
    IView mView; @Inject TestModel mModel;//Dagger2遇到@Inject标记的成员属性,就会去查看该成员类的构造函数,如果构造函数也被@Inject标记,则会自动初始化,完成依赖注入。 //TestPresent的构造函数也被@Inject注解修饰 @Inject public TestPresent(IView view){ this.mView=view; } public void updateUI(){ mView.updateUI(mModel.getText()); } } / * Model类,实现具体的业务逻辑 */ public class TestModel { 
    //构造函数用@Inject修饰 @Inject public TestModel(){ } public String getText(){ return "Dagger2应用实践..."; } } / * Module类提供那些没有构造函数的类的依赖,如第三方类库,系统类,接口类 */ @Module public class TestModule { 
    private IView mView; public TestModule(IView iView){ this.mView=iView; } //@Provides注解的方法,提供IView类的依赖。 @Provides public IView provideIView(){ return this.mView; } } / *Component必须是一个接口类或者抽象 */ @Component(modules = TestModule.class) public interface TestComponent { 
    void inject(TestActivity testActivity); }

总结:

  • @Inject 如果一个成员变量被@Inject注解修饰,并且它的类型构造函数也被@Inject注解修饰,那么dagger2就可以帮我们实例化该成员类型,并注入。例如:TestActivity类中的mPresent以及TestPresent类中的mModel,都属于这种情况。
  • @Module 注解修饰的类负责提供那些没有构造函数的类的依赖,如第三方类库,系统类,接口类。
  • @Provides 注解修饰的方法,必须以provide开头后跟提供的依赖类型。负责提供具体类型的依赖,一个@Module修饰的类可以有多个@Provides修饰的方法。
  • @Component 注解修饰的接口或抽象类,负责在@Inject和@Module之间建立连接,当实例化@Inject注解的类时,遇到没有构造函数的成员变量依赖,则该依赖由@Module修饰的类提供。inject方法用于获取TestActivity的实例。

看到这里小伙伴们大概已经知道如何使用dagger2了。但对于代码为何这样写,dagger2内部是怎么帮我们实现各个类间的依赖注入的还不是很清楚。接下来,我们就进入到dagger2为我们生成类的源码中看看,dagger2分别为我们实现了那些类,这些类之间是如何协作来帮助我们实现依赖注入的。

Dagger2原理分析

DaggerTestComponent.builder().testModule(new TestModule(this)).build().inject(this);//@Component连接起@Inject@Module的关键

DaggerTestComponent,这是什么鬼,我们好像没有定义过这个类啊,别急,这个dagger2根据@Component注解帮我们生成的类,我们进去看看它具体做了什么工作。

DaggerTestComponent源码:

/ 1. dagger2根据@Component注解帮我们生成的类,实现我们定义的TestComponent接口 */ public final class DaggerTestComponent implements TestComponent { 
    private MembersInjector 
  
    testPresentMembersInjector; 
   //负责注入TestPresent中被@Inject注解修饰的的成员变量的依赖。dagger2会为TestPresent生成一个TestPresent_MembersInjector类,专门负责TestPresent中@Inject注解的依赖注入 
   private Provider 
   
     provideIViewProvider; 
    //负责注入TestPresent中没有构造函数的成员变量的依赖。dagger2会依据@Component中传入的modules值(示例中为TestModule),为Module类中@Provides修饰的方法(示例中为provideIView)提供一个TestModule_ProvideIViewFactory类 
    private Provider 
    
      testPresentProvider; 
     //提供TestActivity中TestPresent类型的依赖 
     private MembersInjector 
     
       testActivityMembersInjector; 
      //负责注入TestActivity中@Inject修饰的成员变量 
      private 
      DaggerTestComponent(Builder builder) { 
      assert builder != 
      null; initialize(builder); } 
      public 
      static Builder 
      builder() { 
      return 
      new Builder(); } 
      @SuppressWarnings( 
      "unchecked") 
      private 
      void 
      initialize( 
      final Builder builder) { 
      this.testPresentMembersInjector = TestPresent_MembersInjector.create(TestModel_Factory.create()); 
      //创建TestModel_Factory实例,再根据生成的TestModel_Factory实例创建TestPresent_MembersInjector的实例 
      this.provideIViewProvider = TestModule_ProvideIViewFactory.create(builder.testModule); 
      //通过传入的TestModule实例创建TestModule_ProvideIViewFactory的实例 
      this.testPresentProvider = TestPresent_Factory.create(testPresentMembersInjector, provideIViewProvider); 
      //根据testPresentMembersInjector和provideIViewProvider创建TestPresent_Factory的实例 
      this.testActivityMembersInjector = TestActivity_MembersInjector.create(testPresentProvider); 
      //根据testPresentProvider创建TestActivity_MembersInjector的实例 } 
      @Override 
      public 
      void 
      inject(TestActivity testActivity) { testActivityMembersInjector.injectMembers(testActivity); 
      //调用testActivityMembersInjector的injectMembers方法为TestActivity提供依赖注入 } 
      public 
      static 
      final 
      class Builder { 
        
      private TestModule testModule; 
      private 
      Builder() {} 
      public TestComponent 
      build() { 
      if (testModule == 
      null) { 
      throw 
      new IllegalStateException(TestModule.class.getCanonicalName() + 
      " must be set"); } 
      return 
      new DaggerTestComponent( 
      this); } 
      //传入TestModule的实例 
      public Builder 
      testModule(TestModule testModule) { 
      this.testModule = Preconditions.checkNotNull(testModule); 
      return 
      this; } } } 
      
     
    
  

可以看到,dagger2为TestActivity实现依赖注入的步骤大概如下:

  1. 根据@Component注解生成Dagger开头的DaggerXxxComponent类(示例中为DaggerTestComponent类)
  2. 根据@Component注解中传入的modules值(示例中为TestModule.class),在DaggerXxxComponent的静态内部类Builder中生成相应的xxxModule方法,传入Module的实例。
  3. 实现@Component注解接口XxxComponent(示例中为TestComponent)中的inject方法,传入TestActivity的示例。

此时,dagger2已经通过@Component关联起了@Inject和@Module注解。但是具体是怎么注入的我们还不是很清楚,我们看到inject方法中调用testActivityMembersInjector的injectMembers()方法完成了对TestActivity的依赖注入,我们再看TestActivity_MembersInjector的源码:

/ * dagger2根据TestActivity中的@Inject注解生成的成员注入类 */ public final class TestActivity_MembersInjector implements MembersInjector 
  
    { 
   private final Provider 
   
     mPresentProvider; 
    public 
    TestActivity_MembersInjector(Provider 
    
      mPresentProvider) { assert mPresentProvider != 
     null; 
     this.mPresentProvider = mPresentProvider; 
     //将create方法中传入的mPresentProvider赋值mPresentProvider } 
     //mPresentProvider即为DaggerTestComponent中创建的TestPresent_Factory的实例testPresentProvider 
     public 
     static MembersInjector 
      
      create(Provider 
      
        mPresentProvider) { 
       return 
       new TestActivity_MembersInjector(mPresentProvider); } 
       //依赖注入方法,在DaggerTestComponent的inject方法中被调用 @Override 
       public 
       void 
       injectMembers(TestActivity instance) { 
       if (instance == 
       null) { 
       throw 
       new NullPointerException( 
       "Cannot inject members into a null reference"); } instance.mPresent = mPresentProvider. 
       get(); 
       //通过mPresentProvider的get方法获取到TestPresent的实例并赋值给TestActivity中的mPresent } 
       public 
       static 
       void 
       injectMPresent(TestActivity instance, Provider 
       
         mPresentProvider) { instance.mPresent = mPresentProvider. 
        get(); } } 
        
       
      
     
    
  

可以看到,上面代码中是通过mPresentProvider(TestPresent_Factory的实例)的get方法获取到TestPresent的实例并复制给TestActivity中的mPresent,TestPresent_Factory的源码:

/ * dagger2生成的TestPresent工厂类 */ public final class TestPresent_Factory implements Factory<TestPresent> { 
    private final MembersInjector 
  
    testPresentMembersInjector; 
   //提供TestPresent中@Inject注解修饰的成员变量的依赖 
   private 
   final Provider 
   
     viewProvider; 
    //提供TestPresent中不能被@Inject修饰的成员变量(变量类型没有构造函数或构造函数上无法加@Inject注解)的依赖 
    public TestPresent_Factory( MembersInjector 
    
      testPresentMembersInjector, Provider 
     
       viewProvider) { assert testPresentMembersInjector != 
      null; 
      this.testPresentMembersInjector = testPresentMembersInjector; assert viewProvider != 
      null; 
      this.viewProvider = viewProvider; } @Override 
      public TestPresent get() { 
      //首先根据传入的viewProvider中的get方法获取到IView实例,创建TestPresent的实例, 
      // 再通过MemberInjectors.injecMembers方法,为创建的TestPreset实例注入@Inject修饰的成员变量(mModule) 
      //然后返回创建的TestPresent实例 
      return MembersInjectors.injectMembers( testPresentMembersInjector, 
      new TestPresent(viewProvider.get())); } 
      //此处传入的testPresentMemberInjector即为DaggerTestComponent中创建的TestPresent_MembersInjector的实例 
      //viewProvider即为DaggerTestComponent中创建的TestModule_ProvideIViewFactory的实例 
      public 
      static Factory 
      
        create( MembersInjector 
       
         testPresentMembersInjector, Provider 
        
          viewProvider) { 
         return 
         new TestPresent_Factory(testPresentMembersInjector, viewProvider); } } 
         
        
       
      
     
    
  

TestPresent_Factory中通过viewProvider的get方法获取到IView的实例,此处的viewProvider即为DaggerTestComponent中传入的TestModule_ProvideIViewFactory实例:

/ * dagger2为@Module修饰的类中的每个@Provides修饰的方法生成的类 */ public final class TestModule_ProvideIViewFactory implements Factory<IView> { 
    private final TestModule module; public TestModule_ProvideIViewFactory(TestModule module) { assert module != null; this.module = module; } @Override public IView get() { return Preconditions.checkNotNull( module.provideIView(), "Cannot return null from a non-@Nullable @Provides method");//通过传入的TestModule实例的provideIView方法获取IView的实例并返回 } //此处的module即为TestActivity中通过DaggerTestComponet.Builder().testModule()方法传入的TestModule实例 public static Factory 
  
    create(TestModule module) { 
   return 
   new TestModule_ProvideIViewFactory(module); } } 
  

TestPresent_Factory中通过MembersInjectors中的injectMembers方法,为创建的TestPresent注入@Inject修饰的成员变量(mModel)的依赖。MembersInjectors的源码:

public final class MembersInjectors { public static 
  
    T 
   injectMembers(MembersInjector 
   
     membersInjector, T instance) { membersInjector.injectMembers(instance); 
    //membersInjector为DaggerTestComponent中传入的TestPresent_MembersInjector的实例testPresentMembersInjector,实际上调用的是TestPresent_MembersInjector的injectMembers()方法 
    return instance; } } 
    
  

TestPresent_MembersInjector的源码:

public final class TestPresent_MembersInjector implements MembersInjector 
  
    { 
   private final Provider 
   
     mModelProvider; 
    public 
    TestPresent_MembersInjector(Provider 
    
      mModelProvider) { assert mModelProvider != 
     null; 
     this.mModelProvider = mModelProvider; } 
     public 
     static MembersInjector 
      
      create(Provider 
      
        mModelProvider) { 
       //mModelProvider为DaggerTestComponent中传入的TestModel_Factory的实例 
       return 
       new TestPresent_MembersInjector(mModelProvider); } @Override 
       public 
       void 
       injectMembers(TestPresent instance) { 
       if (instance == 
       null) { 
       throw 
       new NullPointerException( 
       "Cannot inject members into a null reference"); } instance.mModel = mModelProvider. 
       get(); 
       //通过mModelProvider的get方法获取到TestModel的实例并赋值给TestPresent实例中的mModel。 } 
       public 
       static 
       void 
       injectMModel(TestPresent instance, Provider 
       
         mModelProvider) { instance.mModel = mModelProvider. 
        get(); } } 
        
       
      
     
    
  

TestModel_Factory源码:

public enum TestModel_Factory implements Factory 
  
    { INSTANCE; 
   @Override 
   public TestModel 
   get() { 
   return 
   new TestModel(); 
   //返回TestModel的实例 } 
   public 
   static Factory 
    
    create() { 
    return INSTANCE; 
    //返回TestModel_Factory的实例 } } 
    
  

至此,我们完整分析了Dagger2为我们实现依赖注入的全过程,相信大家对Dagger2为我们实现依赖注入的原理有了一定的了解。有什么不解的欢迎大家在评论区给我留言,我会尽量作答。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

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

(0)
上一篇 2026年3月18日 上午7:55
下一篇 2026年3月18日 上午7:55


相关推荐

发表回复

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

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