美文网首页Hello Worldandroid技术
Dagger2从入门到放弃再到恍然大悟

Dagger2从入门到放弃再到恍然大悟

作者: littleKang | 来源:发表于2016-05-26 23:51 被阅读89351次

    写在前面:
    我目前就职于阿里巴巴-菜鸟,团队目前缺人,招聘java和客户端开发,招聘对象为:社招和19届毕业的校招生,有适合的人选发送简历到我个人邮箱:hsk256@163.com,谢谢大家。

    现在Dagger2在项目里用的越来越多了,最近花了些时间学习了一下Dagger2,这篇文章主要帮助理解Dagger2的注入实现过程,如有错误,还请指正!

    什么是Dagger2

    Dagger2是Dagger的升级版,是一个依赖注入框架,现在由Google接手维护。 恩,这里有个关键字依赖注入,因此我们得先知道什么是依赖注入,才能更好的理解Dagger2。

    依赖注入是面向对象编程的一种设计模式,其目的是为了降低程序耦合,这个耦合就是类之间的依赖引起的。

    举个例子:我们在写面向对象程序时,往往会用到组合,即在一个类中引用另一个类,从而可以调用引用的类的方法完成某些功能,就像下面这样.

    public class ClassA {
        ...
        ClassB b;
        ...
        public ClassA() {
            b = new ClassB();
        }
        
        public void do() {
            ...
            b.doSomething();
            ...
        }
    }
    

    这个时候就产生了依赖问题,ClassA依赖于ClassB,必须借助ClassB的方法,才能完成一些功能。这样看好像并没有什么问题,但是我们在ClassA的构造方法里面直接创建了ClassB的实例,问题就出现在这,在ClassA里直接创建ClassB实例,违背了单一职责原则,ClassB实例的创建不应由ClassA来完成;其次耦合度增加,扩展性差,如果我们想在实例化ClassB的时候传入参数,那么不得不改动ClassA的构造方法,不符合开闭原则

    因此我们需要一种注入方式,将依赖注入到宿主类(或者叫目标类)中,从而解决上面所述的问题。依赖注入有一下几种方式:

    • 通过接口注入

      interface ClassBInterface {
          void setB(ClassB b);
      }
      
      public class ClassA implements ClassBInterface {
          ClassB classB;
          
          @override
          void setB(ClassB b) {
              classB = b;
          }
      }
      
    • 通过set方法注入

      public class ClassA {
          ClassB classB;
          
          public void setClassB(ClassB b) {
              classB = b;
          }
      }
      
    • 通过构造方法注入

      public class ClassA {
          ClassB classB;
          
          public void ClassA(ClassB b) {
              classB = b;
          }
      
    • 通过Java注解

      public class ClassA {
          //此时并不会完成注入,还需要依赖注入框架的支持,如RoboGuice,Dagger2
          @inject ClassB classB;
          
          ...
          public ClassA() {}
      

    在Dagger2中用的就是最后一种注入方式,通过注解的方式,将依赖注入到宿主类中。

    如何引入Dagger2

    • 配置apt插件(在build.gradle(Project:xxx)中添加如下代码)

      dependencies {
          classpath 'com.android.tools.build:gradle:2.1.0'
          //添加apt插件
          classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
         
      }
      
    • 添加依赖(在build.gradle(Module:app)中添加如下代码)

      apply plugin: 'com.android.application'
      //添加如下代码,应用apt插件
      apply plugin: 'com.neenbedankt.android-apt'
      ...
      dependencies {
          ...
          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

    下面用一个栗子来说明,如何使用Dagger2,需要说明的是,这个栗子是基于mvp模式的,所以如果还不了解mvp的话,可以先去了解mvp,再继续看下面的内容。

    在mvp中,最常见的一种依赖关系,就是Activity持有presenter的引用,并在Activity中实例化这个presenter,即Activity依赖presenter,presenter又需要依赖View接口,从而更新UI,就像下面这样:

    public class MainActivity extends AppCompatActivity implements MainContract.View {
        private MainPresenter mainPresenter;
        ...
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //实例化presenter 将view传递给presenter
            mainPresenter = new MainPresenter(this);
            //调用Presenter方法加载数据
             mainPresenter.loadData();
             
             ...
        }
    
    }
    
    public class MainPresenter {
        //MainContract是个接口,View是他的内部接口,这里看做View接口即可
        private MainContract.View mView;
        
        MainPresenter(MainContract.View view) {
            mView = view;
        }
        
        public void loadData() {
            //调用model层方法,加载数据
            ...
            //回调方法成功时
            mView.updateUI();
        }
    
    

    这样Activity与presenter仅仅耦合在了一起,当需要改变presenter的构造方式时,需要修改这里的代码。如果用依赖注入的话,是这样的:

    
    public class MainActivity extends AppCompatActivity implements MainContract.View {
        @Inject
        MainPresenter mainPresenter;
        ...
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
             
             DaggerMainComponent.builder()
                    .mainModule(new MainModule(this))
                    .build()
                    .inject(this);
            //调用Presenter方法加载数据
             mainPresenter.loadData();
             
             ...
        }
    
    }
    
    public class MainPresenter {
        //MainContract是个接口,View是他的内部接口,这里看做View接口即可
        private MainContract.View mView;
        
        @Inject
        MainPresenter(MainContract.View view) {
            mView = view;
        }    
        public void loadData() {
            //调用model层方法,加载数据
            ...
            //回调方法成功时
            mView.updateUI();
        }
    
    @Module
    public class MainModule {
        private final MainContract.View mView;
    
        public MainModule(MainContract.View view) {
            mView = view;
        }
    
        @Provides
        MainView provideMainView() {
            return mView;
        }
    }
    
    @Component(modules = MainModule.class)
    public interface MainComponent {
        void inject(MainActivity activity);
    }
    
    

    额,貌似变得更复杂了,还不如不用Dagger2呢。不过仔细想想也是可以理解的,直接组合方式虽然简单,但是具有耦合性,为了解决这种耦合,可能就会多产生一些辅助类,让这种直接的依赖关系,变为间接,降低耦合。跟大多数设计模式一样,为了达到高内聚低耦合,往往会有很多接口与类,Daager2也是如此,虽然看似复杂了些,不过这在软件工程中是值得的。下面,就来分析下上面代码是什么意思。

    我们先看MainActivity里的代码,之前是直接声明MainPresenter,现在在声明的基础上加了一个注解@Inject,表明MainPresenter是需要注入到MainActivity中,即MainActivity依赖于MainPresenter,这里要注意的是,使用@Inject时,不能用private修饰符修饰类的成员属性。

    然后我们在MainPresenter的构造函数上同样加了@Inject注解。这样MainActivity里的mainPresenter与他的构造函数建立了某种联系。这种联系我们可以这样理解,当看到某个类被@Inject标记时,就会到他的构造方法中,如果这个构造方法也被@Inject标记的话,就会自动初始化这个类,从而完成依赖注入。

    然后,他们之间并不会凭空建立起联系,因此我们想到,肯定需要一个桥梁,将他们连接起来,也就是下面要介绍的Component。

    Component是一个接口或者抽象类,用@Component注解标注(这里先不管括号里的modules),我们在这个接口中定义了一个inject()方法,参数是Mainactivity。然后rebuild一下项目,会生成一个以Dagger为前缀的Component类,这里是DaggerMainComponent,然后在MainActivity里完成下面代码.

    DaggerMainComponent.builder()
                    .mainModule(new MainModule(this))
                    .build()
                    .inject(this);
    

    此时Component就将@Inject注解的mainPresenter与其构造函数联系了起来。此时,看到这里,如果是初学者的话,一定会非常迷惑,究竟是怎么建立起联系的,实例化过程在哪?别急,后面会讲解这个过程原理的。

    此时我们已经完成了presenter的注入过程,但是我们发现还有一个MainModule类,这个类是做什么的?MainModlue是一个注解类,用@Module注解标注,主要用来提供依赖。等等,刚才通过@Inject就可以完成依赖,为什么这里还要用到Module类来提供依赖?之所以有Module类主要是为了提供那些没有构造函数的类的依赖,这些类无法用@Inject标注,比如第三方类库,系统类,以及上面示例的View接口。

    我们在MainModule类里声明了MainContract.View成员属性,在构造方法里将外界传进来的view赋值给mView,并通过一个@Provides标注的以provide开头的方法,将这个view返回,这个以provide开头的方法就是提供依赖的,我们可以创建多个方法来提供不同的依赖。那么这个类究竟是怎么作用的?可以想到上面提到的@Component注解括号里的东西了。就是下面这个

    @Component(modules = MainModule.class)
    public interface MainComponent {
        void inject(MainActivity activity);
    }
    

    所以Module要发挥作用,还是要依靠于Component类,一个Component类可以包含多个Module类,用来提供依赖。我们接着看下面这段代码:

    DaggerMainComponent.builder()
                    .mainModule(new MainModule(this))
                    .build()
                    .inject(this);
    

    这里通过new MainModule(this)将view传递到MainModule里,然后MainModule里的provideMainView()方法返回这个View,当去实例化MainPresenter时,发现构造函数有个参数,此时会在Module里查找提供这个依赖的方法,将该View传递进去,这样就完成了presenter里View的注入。

    我们来重新理一遍上面的注入过程,首先弄清楚以下几个概念:

    • @Inject 带有此注解的属性或构造方法将参与到依赖注入中,Dagger2会实例化有此注解的类
    • @Module 带有此注解的类,用来提供依赖,里面定义一些用@Provides注解的以provide开头的方法,这些方法就是所提供的依赖,Dagger2会在该类中寻找实例化某个类所需要的依赖。
    • @Component 用来将@Inject和@Module联系起来的桥梁,从@Module中获取依赖并将依赖注入给@Inject

    接着我们重新回顾一下上面的注入过程:首先MainActivity需要依赖MainPresenter,因此,我们在里面用@Inject对MainPresenter进行标注,表明这是要注入的类。然后,我们对MainPresenter的构造函数也添加注解@Inject,此时构造函数里有一个参数MainContract.View,因为MainPresenter需要依赖MainContract.View,所以我们定义了一个类,叫做MainModule,提供一个方法provideMainView,用来提供这个依赖,这个MainView是通过MainModule的构造函数注入进来的,接着我们需要定义Component接口类,并将Module包含进来,即

    @Component(modules = MainModule.class)
    public interface MainComponent {
        void inject(MainActivity activity);
    }
    

    同时里面声明了一个inject方法,方法参数为ManActivity,用来获取MainActivity实例,以初始化在里面声明的MainPresenter

    DaggerMainComponent.builder()
                    .mainModule(new MainModule(this))
                    .build()
                    .inject(this);
    

    此时,注入过程就完成了,或许到此时,还是会有一些疑惑,因为我们看不到实例化的过程在哪里,为什么要这样去写代码,所以下面,就基于这个实例,分析Dagger2内部究竟做了什么。

    Dagger2注入原理

    Dagger2与其他依赖注入框架不同,它是通过apt插件在编译阶段生成相应的注入代码,下面我们就具体看看Dagger2生成了哪些注入代码?

    我们先看MainPresenter这个类,在这个类中我们对构造方法用了@Inject标注,然后Rebuild Project,Dagger2会在/app/build/generated/apt/debug/目录下生成一个对应的工厂类MainPresenter_Factory,我们看下面具体代码(为了方便理解,我把MainPresenter也贴了出来)

    public class MainPresenter {
        MainContract.View mView;
        @Inject
        MainPresenter(MainContract.View view) {
            mView = view;
        }
     }
    
    
    public final class MainPresenter_Factory implements Factory<MainPresenter> {
      private final Provider<MainContract.View> viewProvider;
    
      public MainPresenter_Factory(Provider<MainContract.View> viewProvider) {
        assert viewProvider != null;
        this.viewProvider = viewProvider;
      }
    
      @Override
      public MainPresenter get() {
        return new MainPresenter(viewProvider.get());
      }
    
      public static Factory<MainPresenter> create(Provider<MainContract.View> viewProvider) {
        return new MainPresenter_Factory(viewProvider);
      }
    }
    

    对比MainPresenter,我们发现在MainPre_Factory里也生成了对应的代码。首先是viewProvide,这是一个Provider类型,泛型参数就是我们的MainContract.View,接着通过构造方法,对viewProvider进行实例化。其实这里有个疑惑,上面的成员属性为什么不直接是MainContract.View,而是Provider类型?看到provider我们应该想到这个MainContract.View是一个依赖,而依赖的提供者是MainModule,因此这个viewProvider一定是由MainModul提供的。我们接着看下面的get()方法,看到这个方法,我想我们有点恍然大悟的感觉,原来MainPresenter的实例化就在这里,构造函数里的参数就是我们依赖的MainContract.View,它是由viewProvider通过get()提供。接着是一个create()方法,并且有一个参数viewProvider,用来创建这个MainPresenter_Factory类。

    上面我们得出,viewProvider是由MainModule提供的,所以我们接着看MainModule所对应的注入类。

    @Module
    public class MainModule {
        private final MainContract.View mView;
    
        public MainModule(MainContract.View view) {
            mView = view;
        }
    
        @Provides
        MainContract.View provideMainView() {
            return mView;
       }   
    }
    
    
    public final class MainModule_ProvideMainViewFactory implements Factory<MainContract.View> {
      private final MainModule module;
    
      public MainModule_ProvideMainViewFactory(MainModule module) {
        assert module != null;
        this.module = module;
      }
    
      @Override
      public MainContract.View get() {
        return Preconditions.checkNotNull(
            module.provideMainView(), "Cannot return null from a non-@Nullable @Provides method");
      }
    
      public static Factory<MainContract.View> create(MainModule module) {
        return new MainModule_ProvideMainViewFactory(module);
      }
    }
    
    

    看到上面的类名,我们发现了一种对应关系,在MainModule中定义的@Provides修饰的方法会对应的生成一个工厂类,这里是MainModule_ProvideMainViewFactory。我们看到这个类里有一个get()方法,其中调用了MainModule里的provideMainView()方法来返回我们所需要的依赖MainContract.View。还记得在MainPresenter_Factory里的get()方法中,实例化MainPresenter时候的参数viewProvider.get()吗?到这里我们就明白了,原来那个viewProvider就是生成的MainModule_ProvideMainViewFactory,然后调用了其get()方法,将我们需要的MainContract.View注入到MainPresenter里。

    看到这里我们应该明白了MainPresenter的实例化过程。MainPresenter会对应的有一个工厂类,在这个类的get()方法中进行MainPresenter创建,而MainPresenter所需要的View依赖,是由MainModule里定义的以provide开头的方法所对应的工厂类提供的。

    虽然我们明白了实例化的创建过程,但是此时还是有点疑惑,MainPresenter_Factory的创建是由create()完成的,那么crate是在哪调用的,此时创建的MainPresenter实例是怎么跟@Inject注解的MainPresenter关联起来的,我想你已经知道了答案,没错就是Component。前面说过Component是连接@Module和@Inject的桥梁,所以上面的疑惑就要到编译后Component所对应的类中寻找答案。

    @Component(modules = MainModule.class)
    public interface MainComponent {
        void inject(MainActivity activity);
    }
    
    public final class DaggerMainComponent implements MainComponent {
      private Provider<MainContract.View> provideMainViewProvider;
    
      private Provider<MainPresenter> mainPresenterProvider;
    
      private MembersInjector<MainActivity> mainActivityMembersInjector;
    
      private DaggerMainComponent(Builder builder) {
        assert builder != null;
        initialize(builder);
      }
    
      public static Builder builder() {
        return new Builder();
      }
    
      @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
    
        this.provideMainViewProvider = MainModule_ProvideMainViewFactory.create(builder.mainModule);
    
        this.mainPresenterProvider = MainPresenter_Factory.create(provideMainViewProvider);
    
        this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainPresenterProvider);
      }
    
      @Override
      public void inject(MainActivity activity) {
        mainActivityMembersInjector.injectMembers(activity);
      }
    
      public static final class Builder {
        private MainModule mainModule;
    
        private Builder() {}
    
        public MainComponent build() {
          if (mainModule == null) {
            throw new IllegalStateException(MainModule.class.getCanonicalName() + " must be set");
          }
          return new DaggerMainComponent(this);
        }
    
        public Builder mainModule(MainModule mainModule) {
          this.mainModule = Preconditions.checkNotNull(mainModule);
          return this;
        }
      }
    }
    
    

    从上面代码看到定义的MainComponent会生成一个对应的DaggerMainComponent,并且实现了MainComponent里的方法。我们看到代码中又出现了Provide类型的成员属性,前面说过这个Provide类型就是所提供的依赖,我们在看它们是在哪实例化的。我们看到有一个initialize()方法

    
    @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
    
        this.provideMainViewProvider = MainModule_ProvideMainViewFactory.create(builder.mainModule);
    
        this.mainPresenterProvider = MainPresenter_Factory.create(provideMainViewProvider);
    
        this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainPresenterProvider);
      }
      
    

    看到这估计就明白了刚才的疑惑。首先创建了MainModule_ProvideMainViewFactory实例,用来提供MainContract.View依赖。这里可能有个小疑惑,create()方法返回的是Factory类型,而provideMainViewProvider是个Provider类型,其实看源码就明白了,Factory继承自Provider。

    public interface Factory<T> extends Provider<T> {
    }
    

    然后将provideMainViewProvider传递到MainPresenter_Factory里,即就是前面讲到的viewProvider。接着将这个mainPresenterProvider又传递到MainActivity_MembersInjector中进行实例化,我们看到这个类前面是MainActivity开头,因此可以想到是MainActivity对应得注入类,我们后面再分析这个类。

    接着是我们在MainComponent里定义的Inject方法的实现,这里调用了mainActivityMembersInjector.injectMembers(activity)方法,将我们的MainActivity注入到该类中。

    接着就是Builder内部类,用来创建我们的module以及自身实例。所以在DaggerMainComponent里主要用来初始化依赖,而真正的将这些依赖于Inject关联起来的就是刚才的MainActivity_MembersInjector类,我们看看这个类里做了什么。

    public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
      private final Provider<MainPresenter> mainPresenterProvider;
    
      public MainActivity_MembersInjector(Provider<MainPresenter> mainPresenterProvider) {
        assert mainPresenterProvider != null;
        this.mainPresenterProvider = mainPresenterProvider;
      }
    
      public static MembersInjector<MainActivity> create(
          Provider<MainPresenter> mainPresenterProvider) {
        return new MainActivity_MembersInjector(mainPresenterProvider);
      }
    
      @Override
      public void injectMembers(MainActivity instance) {
        if (instance == null) {
          throw new NullPointerException("Cannot inject members into a null reference");
        }
        instance.mainPresenter = mainPresenterProvider.get();
      }
    
      public static void injectMainPresenter(
          MainActivity instance, Provider<MainPresenter> mainPresenterProvider) {
        instance.mainPresenter = mainPresenterProvider.get();
      }
    }
    

    这个类的关键就是injectMembers()方法,还记得这个方法在哪调用吗?我想你肯定记得,就在刚才提到的DaggerMainComponent类中的inject()方法里,所以这里的instance实例是由DaggerMainComponent提供的,然后我们看到了最关键的一句代码

    instance.mainPresenter = mainPresenterProvider.get();
    

    看到这,我想应该一切都明白了,将mainPresenterProvider中创建好的MainPresenter实例赋值给instance(MainActivity)的成员mainPresenter,这样我们用@Inject标注的mainPresenter就得到了实例化,接着就可以在代码中使用了。

    到这里,就分析完了Dagger2的注入过程,如果不去看这些生成的类,就很难理解整个过程究竟是怎么发生的,从而导致还是不知道怎么去使用这个依赖注入框架。所以重点去理解这个内部实现原理是非常重要的,刚开始学的时候也是一脸懵逼,总搞不太清之间的关系,不知道究竟怎么写,弄懂了整个来龙去脉后,发现就知道怎么去运用了。

    关于Dagger2的其他使用就不多讲了,可以看其他的优秀博客,我会再后面附上链接,方便学习。Dagger2就是一个依赖注入工具,至于怎么使用完全在个人,所以不必纠结到底怎么去写才是正确的,只要弄懂原理,灵活运用,能够做到尽可能解耦,适合自己的业务就是最好的写法。

    感谢:

    http://www.jianshu.com/p/cd2c1c9f68d4

    http://alighters.com/blog/2016/04/15/dagger2-indepth-understanding/

    http://chriszou.com/2016/05/10/android-unit-testing-di-dagger.html

    http://blog.nimbledroid.com/2016/03/07/performance-of-dependency-injection-libraries-zh.html

    http://google.github.io/dagger/

    招聘:
    我目前就职于阿里巴巴-菜鸟,团队目前缺人,招聘java和客户端开发,招聘对象为:社招和19届毕业的校招生,有适合的人选发送简历到我个人邮箱:hsk256@163.com,谢谢大家。

    相关文章

      网友评论

      • April_zzd:https://www.jianshu.com/p/368b8fc2bb38 楼主,有人抄袭你的文章不注明出处
      • 943fc9232164:为何如此般优秀。:wink:
      • 久伴_8fef:小哥哥 我可以转载你的这篇文章吗?我会注明的!
      • Jay_Lwp:androidstudio 3.0以上怎么rebuild没生成DaggerMainComponent这?我定义的就是MainComponent
      • 学费:棒,非常详细。
      • 一凡和梓墨:楼主写的很棒啊,简单易懂,么么哒
      • 我打过猴:写的很棒,对于dagger2小白来讲也能看懂。赞
      • tmyzh:DaggerMainComponent这个类为什么没找到啊
        tmyzh:@dalvik 老哥 我不记得了 我最后好像放弃了 因为我真的引入自己的mvp不习惯 还是用的黄油刀
        f7ea2720c392:同问,你的这个最后找到了?
      • 爱吃猫的咸鱼:写的很棒 可我还是看的云里雾里 哎 我这逻辑思维...
      • 1d41aa4a5cec:浅显易懂
      • lebonbill:终于看懂了,谢谢老哥分享哦
      • MisterT:勘误:
        通过构造方法注入

        public class ClassA {
        ClassB classB;

        public void ClassA(ClassB b) {// 构造方式,这里多了void
        classB = b;
        }
      • 丶微米米米:简单明了,基础入门,赞
      • AbTian:写的太棒了,浅显易懂!
      • Jafir:可以 算是我看过讲得很清楚的文章了
        但是有个问题
        public static void injectMainPresenter(
        MainActivity instance, Provider<MainPresenter> mainPresenterProvider) {
        instance.mainPresenter = mainPresenterProvider.get();
        }
        memberInjector里面的这个静态方法,好像没有被调用,什么情况下被使用,用在何处,楼主可否知晓?
      • ShawnPeng:这是我看到关于讲解Dagger最详尽易懂的文章,而且这种语言风格我也是特别喜欢。楼主:+1: :pray:
      • 木子而东:@singleton
        @Component(modules = {AppModule.class})
        public interface AppComponent {

        ToastUtil ToastUtil();

        像这种的为啥要在appcomponent中写ToastUtil() 方法,是因为其他模块或者界面需要使用吗?
      • 23ce6bdbd300:楼主写的是真心不错,谢谢了!看了你的文章后,基本了解了,特地注册后来表示感谢~
      • Cpb:谢谢楼主。
      • wishes丶啊:这就是传说中的mvvp吗
      • this_is_for_u:mainModule是怎么出来的呢
      • 戴定康:原理让我看晕了
      • cd147c1a24b7:请问MaiModule类的provideMainView方法是不是应该写成provideMainPresenter并且返回MainPresenter的实例?结合其他地方的dagger知识感觉这个地方有些冲突,谢谢!
      • b93cf666b122:MVP的点不开啦?很捉急啊楼主,能解决一下吗?或者给个其他路径,但是最好还是那篇文章!
      • duckmoon:👍,但是后面的链接地址不对啊
      • ebaba8486bd2:写的很好,谢谢
      • 兔斯基第2号:没看到MainContract的实现代码
      • jackylee2:写的非常清晰:+1:
      • 戴定康:后面那段完全看不懂好吗
      • 待我所待:这个可以理解成将activity和presenter之间的耦合转化为了activity和module之间的耦合吗?如果presenter的构造函数需要多个参数,那个Module的构造函数中的参数也会变多,那么module之间的耦合不也会加重吗?
        HumorousMan:@HarrisGong 那感觉这个和presenter构造函数更新也并没有什么太大的不同啊?我也是同样不太理解这块
        HarrisGong:用dagger2之前,如果presenter的构造函数发生改变,所有和presenter构造函数相关的代码都要改变。
        用dagger2之后,只需要更新Module的构造函数中的参数即可。
        HarrisGong:同问
      • 804dba5f7540:我想问一下你说的接口注入具体怎么实现呢,ClassB 类在哪里实例化呢,怎么去实例化ClassB对象呢
      • 戴定康:你在哔哩哔哩上班吗
      • android_cyw:提示一下博主,后面给出的超链接错了,有好几条都链接到了本文
      • crazyandcoder:dagger2上手比较困难,这篇文章讲解的不错,通俗易懂,简洁!谢谢
      • 风影_638f:先赞为敬
      • feng__:没看懂MainView是怎么来的
      • 暮雨沉沦:~\(≧▽≦)/~感谢
      • boboyuwu:弄懂了Dagger2原理再来看这个呼伦灌顶但是 不知道是不是我们的版本不一样还是怎么回事我觉得你这源码有点问题你看看哈
        public final class MainPresenter_Factory implements Factory<MainPresenter> {
        private final Provider<MainContract.View> viewProvider;
        // 问题在这
        这里构造我这是Module module 我也觉得应该是这个
        public MainPresenter_Factory(Provider<MainContract.View> viewProvider) {
        assert viewProvider != null;
        this.viewProvider = viewProvider;
        }

        @Override
        public MainPresenter get() {
        这里是调用 module.getDemoPresenter()获得Presenter 估计我们的版本不一样
        return new MainPresenter(viewProvider.get());
        }

        public static Factory<MainPresenter> create(Provider<MainContract.View> viewProvider) {
        return new MainPresenter_Factory(viewProvider);
        }
        }
        boboyuwu:看了以下生成代码 现在版本Dagger感觉生成代码比你那精简了不少 估计确实是笨笨不一样不过原理都是相同的
      • 古道寒鸦:apt插件gradle2.2以下的才需要对吧
      • boboyuwu:我有个疑问哈 如果Presenter(XXView)构造不是单个的里面是这样的Presenter(XXView,String xxx) 或者更多的那么上面源码分析里
        @Override
        public MainPresenter get() {
        return new MainPresenter(viewProvider.get());
        }
        这里面是单个构造参数 怎么应对多个构造参数呢
      • WuTa0:太棒了:+1:
      • 1ad1e4522b56:感谢楼主,能够提供这么好的文章!
      • Vander丶:写的很棒,很清晰的把 Dagger2的生成过程分享出来,不枉看到2点。支持一波
      • 烧烤摊前卖烧烤:懂了一些,多谢楼主!
      • preCh:你好,你那个mvp的例子我写了会crash,presenter对象仍然是空的
      • 吧主:楼主,这篇文章我给你在公众号原创首发可以吗?感觉大神写的很棒,我想让更多的人看到你的文章。公众号:杨守乐(ysle_0313)
      • 1aa33ff7b024:写的整体还算清晰,有几处和自己理解还是有出入的
      • testthat:写的非常好,赞👍
      • 凌晨风:写的太赞了。。。佩服!
      • Deck方:博主讲解依赖注入时classA构造方法不应该是void类型,还有就是接口注入和set方法注入有什么区别?
      • 叫我贺大人:受教了,已上车。
      • 大天使之剣:写得很好,文字通俗易懂,找了一个下午别的博客,术语扯了一大推,可以看出作者很有耐心。
      • loody:楼主思路很清晰,讲解的也很细致,果然是恍然大悟,赞👍
      • shawn_h:楼主写的很好,非常感谢
        最后代码里有个方法 injectMainPresenter()
        这个是做什么处理的呢,求解~
      • 程序员Anthony:非常不错👌
      • 4632a21deeaa:感谢博主,你提供的思路让我理解怎么回事了。。看来还是要去阅读他生成的源码,然后再看看是根据什么注解生成的,就清晰多了。。
      • 北有花开:相见恨晚
      • 4de75f77fe9b:大哥。多分享啊,感觉你靠谱
      • 4de75f77fe9b:顶啊,看了好多网上的文章,看的我晕头转向,但是看了你的,确实有种恍然大悟的赶脚
      • 做行动的巨人:博主你好,我想问一下,假设,只是假设哈,MainPresenter的构造参数是无参的,所以是不是也没必要写Module和Component了,但为什么不写DaggerXXXComponent....inject(this) 被@Inject标注的presenter却并没有注入进来呢,而却Module提供的那个View对无参的presenter并没起到作用啊?
        4de75f77fe9b: @帅猪 知道为什么了吗?同问
      • Silver_Lee:真的是恍然大悟,很细致的文章,非常感谢!
      • 86db62b87432:想问一下博主,请问Module是每个页面都必须的吗?他是为了解决第三方库的注入,这里是指Dagger2这个库吗?
      • 68768b474bfc:文章思路、讲解都不错。我觉得用Dagger2有一点麻烦就是,每次实例化DaggerXXXComponent的时候没有IDE提示,需要先Rebuild之后才有。
      • Ricky_Chan:我们在使用MVP模式开发的时候,MainActivity通常会依赖presenter的接口,然后在实例化的时候通过接口实例化实现类得到对象,但是在使用dagger的时候MainActivity直接依赖的是presenter的实现类,请问楼主,能直接依赖presenter的接口吗??刚接触dagger,请指导指导。。。
        68768b474bfc:@幼稚的小痴 可以的,但就不能用@Inject标注构造函数的方式了,因为接口是没有构造函数的。可以通过MainModule里面提供一个providePresenter()方法,实例化你需要的Presenter并返回。
      • idioitcbear:楼主,如果我的网络请求的IP换了,所以我要重新create Retrofit对象。这个Dagger2要怎么重新注入呢?
      • KingofGlory:写得确实很好,看了好几遍,博主用心了,感谢
      • 1c78b735aaeb:写的好棒\(^o^)/,一脸懵逼的我居然看懂了
      • c3493f6555ab:博主,如果想要修改MainPresenter的构造器,除了开始的View参数,想要再添加其他的参数,修改构造器后,需要怎么修改MainModule 和MainComponent。才可以正常创建MainPresenter的对象
        c3493f6555ab:@littleKang 嗯,好的。修改上了。谢谢啊,还需要慢慢消化一下。
        littleKang: @会爬树的猪丶 在MainModule里提供那个参数的provide方法
      • 99172b512e9c:赞赞赞
      • 我是老王:-- 在我的编译环境下出错了:
        Error:warning: Ignoring InnerClasses attribute for an anonymous inner class

        build tools :23.0.3
        SDK : 6.0
        JDK: 8.0
        不知道 博主 环境是怎么样的?
      • 洛埋名:感觉简书对代码的支持做得不太友好~
        littleKang: @洛埋名 有点,支持高亮就好了
      • qiujuer:写的非常不错,简单易懂,赞一个。
        qiujuer:@倵佱倵寘胤VS唔准我笑人 😂😂
        全是干货:活捉我老师
        littleKang: @qiujuer 感谢支持,共同进步
      • 胡哈哈哈:完全懂了
      • Marno:如果需要传构造参数怎么弄呢?看了好久没看懂dragger,作者这篇我好像看懂了一些!不错!
        shUID:@Marno @littleKang 我感觉没法动态传参,dragger2参数都是在@provider写死的,需要传2个不同参数值就得多写一个@provider注解的函数,感觉都点短板,不知道理解对不对
        littleKang:@Marno 你指的是在哪传构造参数?

      本文标题:Dagger2从入门到放弃再到恍然大悟

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