• 听说你又一次放弃了Dagger2,来听老夫说道说道


    关于Dagger2是啥,用法网上已经有很多了。不过听说你已经很多次Dagger2从入门到放弃了,来来,让我这个老中医给你治一治。老夫手法纯熟,不会让你有任何痛苦的,放心读下去吧。
    本文同步自 博主的私人博客 wing的地方酒馆

    诊断

    咳咳,看你这架势病的不清,应该是陌生代码恐惧症,你看看下面的代码。会不会害怕。

    private ShipDetailPresenter mShipDetailPresenter;   
    mShipDetailPresenter = DaggerShipDetailComponent.builder()
            .shipDetailModule(new ShipDetailModule(this, this))
            .build()
            .inject();

    喂!!!你怎么跑了,快回来,还没治病呢!!

    用法回顾(注入第一式)

    首先,对于一般来说,想创建一个对象,我们肯定采取new的形式:

    mShipDetailPresenter = new ShipDetailPresenter(context,shipDetailView);

    但是这样耦合度较高,presenter的变化受限于Activity,也就是说假如我们的presenter的参数变成三个了,又要改Activity代码。所以使用Dagger2的好处就很明显了,如果改了构造器,只需要改对应的Module就可以。

    @Module

    上面提到了Module,这是什么呢?其实这是一个提供参数的地方,将new Presenter所需要的参数,写到这里面来了。看示例代码:

    @Module //注解说明这是Module
    public class ShipDetailModule {
      private ShipDeatilContract.View mView;
      private Context mContext;
    
      public ShipDetailModule(ShipDeatilContract.View mView, Context mContext) {
        this.mView = mView;
        this.mContext = mContext;
      }
        //注解说明Provide View 既提供View参数
      @Provides ShipDeatilContract.View getView(){
        return mView;
      }
        //注解说明Provide Context 既提供Context参数
      @Provides Context getContext(){
        return mContext;
      }
    }
    

    这是Module的写法,就是把new Presenter(Context,View)写到了里面。

    @Inject

    Module怎么知道presenter构造器需要几个参数呢,答案是@Inject ,只需要在Presenter的构造器注解@Inject

    public class ShipDetailPresenter implements ShipDeatilContract.Presenter {
      Context context;
      ShipDeatilContract.View shipDetailViewInterface;
      //告知构造求所需参数
      @Inject
      public ShipDetailPresenter(Context context,ShipDeatilContract.View shipDetailViewInterface){
        this.context=context;
        this.shipDetailViewInterface=shipDetailViewInterface;
      }
    

    @Component

    连接Presenter和Module的东东,我们只需要写一个接口,来返回Presenter对象,Dagger2就会自动生成对应的对象给我们。

    //注解标注Component  并且告知需要的module是什么
    @Component(modules = ShipDetailModule.class)
    
    public interface ShipDetailComponent {
        //接口的方法,返回presenter
      ShipDetailPresenter inject();
    
    }

    最终联系

    现在看回第一段代码

       private ShipDetailPresenter mShipDetailPresenter;   
       mShipDetailPresenter = DaggerShipDetailComponent.builder()
            .shipDetailModule(new ShipDetailModule(this, this))
            .build()
            .inject();

    DaggerShipDetailComponent这个类是build之后Dagger2自动为我们生成的类,查看源码它实现了ShipDetialComponent这个方法,所以inject()函数自然会为我们返回一个presenter来啦。

    用法回顾(注入第二式)

    你可能犯嘀咕了,你这种写法不科学!跟我看到的不一样。咳咳,不要急,老夫再给你说另一种用法。这种方法的代码如下:

     @Inject ShipDetailPresenter mShipDetailPresenter;   
       DaggerShipDetailComponent.builder()
            .shipDetailModule(new ShipDetailModule(this, this))
            .build()
            .inject(this);

    对应的Component为:

    public interface ShipDetailComponent {
    
      void inject(ShipDetailActivity);
    
    }

    其他的写法都一样。 此时你心里肯定犯嘀咕了,么么的,你刚才说是inject()返回presenter所以可以赋值,这个void你怎么解释! 是不是又要放弃拉,年轻人,不要轻言放弃,听老夫一言。

    想要知道Dagger2 怎么做的那么神奇,必须知道他的原理,原理怎么看?当然是看他生成的代码呗!

    Dagger2原理

    第一式解密

    首先看第一种方法的原理,找到DaggerShipDetailComponent 发现代码如下:

    public final class DaggerShipDetailComponent implements ShipDetailComponent {
      private Provider<Context> getContextProvider;
    
      private Provider<ShipDeatilContract.View> getViewProvider;
    
      private Provider<ShipDetailPresenter> shipDetailPresenterProvider;
      /** 去处多行代码**/
    }

    可以看到Component确实实现了我们定义的Component,所以他的inject()方法肯定是返回了一个presenter

    @Override
      public ShipDetailPresenter inject() {
        return shipDetailPresenterProvider.get();
      }

    老夫没有骗你吧,至于这个provider如何拿到的newPresenter,这里给你留个家庭作业。现在应该有些头绪了吧,Dagger2没有想象中那么难,对不对?接下来看看让你懵逼的第二式。

    第二式

    直接看生成的代码!在DaggerShipDetailComponent发现了

     public void inject(ShipDetailActivity activity) {
        shipDetailsMembersInjector.injectMembers(activity);
      }

    继续往下看,看到了一个init方法

    private void initialize(final Builder builder) {
    
        this.getContextProvider = ShipDetailModule_GetContextFactory.create(builder.shipDetailModule);
    
        this.getViewProvider = ShipDetailModule_GetViewFactory.create(builder.shipDetailModule);
    //工厂生成provider 用来提供presenter
        this.shipDetailPresenterProvider =
            ShipDetailPresenter_Factory.create(getContextProvider, getViewProvider);
    //生成MembersInjector
        this.shipDetailActivityMembersInjector =
    
          ShipDetailActivity_MembersInjector.create(shipDetailPresenterProvider);
      }

    接下来顺藤摸瓜,找到了ShipDetailActivity_MembersInjector,只看关键部分源码

    
    public final class ShipDetailActivity_MembersInjector
        implements MembersInjector<ShipDetailActivity> {
    
    //进行注入操作
      public static void injectShipDetailPresenter(
          ShipDetailActivity instance, Provider<ShipDetailPresenter> shipDetailPresenterProvider) {
        instance.shipDetailPresenter = shipDetailPresenterProvider.get();
      }
    }

    相信聪明的你已经明白了,为什么返回void还能注入,不知道你有没有发现,第二式的presenter没有用private修饰,在injectShipDetailPresenter(ShipDetailActivity,Provider)的时候将 activity.presenter = Proivider.get()!

    如果让我用两个字来形容的话,我只能说

    太他妈精彩

    嘛,这次会诊就到这里吧,回家记得勤加锻炼,早日康复,再见。

  • 相关阅读:
    【BZOJ5306】染色(HAOI2018)-容斥原理+NTT
    【BZOJ3129】方程(SDOI2013)-容斥原理+扩展Lucas定理
    【BZOJ3876】支线剧情(AHOI&JSOI2014)-有上下界费用流
    【POJ1149】PIGS-最大流+优化建模
    【BZOJ1941】Hide and Seek(SDOI2010)-KD树
    【BZOJ1834】网络扩容(ZJOI2010)-最大流+费用流+拆边
    【BZOJ1927】星际竞速(SCOI2010)-费用流+拆点
    【BZOJ4872】分手是祝愿(六省联考2017)-期望DP
    【BZOJ2879】美食节(NOI2012)-费用流+拆点+动态加边
    JQ简单图片轮播
  • 原文地址:https://www.cnblogs.com/muyuge/p/6333514.html
Copyright © 2020-2023  润新知