Dagger2 的一个原理理解方向


说在前面:别人都是从两个端出发开始连线,而我是从线开始寻找连接的端。


本文仅提供一个思考的方向,是我本人对Dagger2的理解,如若错误请留言指正,3Q。并且本文打算私藏,由于同桌好友需要阅读,姑且公开了吧。

阅读本文前需要先阅读 littleKang 的文章 http://www.jianshu.com/p/39d1df6c877d

1: Component

首先确定我们的目的:为了解耦,我们使用依赖注入的方式,去分离变量的声明和实例化。若分离了实例化,则实例化需要打参数必定是通过某种方式去获得。而下面我要讲的就是这个参数(this)的传递过程。

Component作为连接目标和源的桥梁,所以在Component必定包含了目标和源的引用。所以看Google为我们生成的代码(大部分是工厂类),没错我们直接从这部分代码开始。

// Ours
@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity activity);
}
// Google
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;
    }
  }
}

根据

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

的调用顺序看Google生成的代码,

  • DaggerMainComponent 调用静态方法builder()返回内部静态类Builder的对象
  • 接着调用的是Builder的方法mainModule()去实例化属性mainModule,而调用该方法时this参数传递到了Module
  • 接着调用build()方法,使用静态内部类完成DaggerMainComponent的创建(直到这里可以发现Component已经连接到了Module),值得一说的就是在new DaggerMainComponent时调用了initialize()
  • initialize()中,初始化了三个属性(三个工厂类对象),这里需要注意到的是参数,MainModule_ProvideMainViewFactory的参数是builder,这本类中已经完成builder的初始化;接着下面的两个属性的初始化都是以它上一个的对象作为参数,而且都是实例化完毕的!(直到这里知道,这里没有哪个是没有初始化的, That is good!)
  • 完成了DaggerMainComponent的创建就可以使用inject()方法,该方法中调用了injectMembers()方法,注入activity参数,而改参数是MainActivity给予的,这在理解上完全没问题的。(直到这里可以看到DaggerMainComponent连接MainActivity的苗头了,好像这里没看出连接了啥,嗯,确实是,后面会接着说这个问题)

2: Module

1.中已经知道了Module的工厂类的create()方法被调用,已经实现了初始化,那么我们下面直接从create()方法开始看

// Ours
@Module
public class MainModule {
    private final MainContract.View mView;

    public MainModule(MainContract.View view) {
        mView = view;
    }

    @Provides
    MainContract.View provideMainView() {
        return mView;
   }   
}
// Google
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);
  }
}
  • create()方法调用了改工厂类的初始化方法,而参数module1.中调用该工厂类的ceate()方法时给予的,所以不要再考虑谁给的参数用来实例化
  • 实例化好该工厂类之后,将module.provideMainView()返回,之后就可以供Factory<MainContract.View>的对象获取对象mView

3: Presenter(或者是我们自己创建的类,供宿主(MainActivity)使用的类)

这里是一样的,在1.中调用了create()方法,直接从该方法开始分析

// Ours
public class MainPresenter {
    MainContract.View mView;
    @Inject
    MainPresenter(MainContract.View view) {
        mView = view;
    }
 }
// Google
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);
  }
}
  • create()方法中实例化并返回该工厂类的对象,而该类中的get()方法直接返回我们需要依赖的MainPresenter对象,而实例化所需要的参数在create()方法给出!(还没有思路的话就绕着这个参数返回阅读)
  • 直到这里,我们可以了解这么一个情况,从MainActivity中给予的参数经过一系列的传递,最后传到了MainPresenter()中,那么也就是说,我们直接调用这里的get()方法便可以直接获取MainPresenter类的实例!
  • 那么好,经过一系列的传递后该对象得到了初始化有了,然而怎么讲这么实例传回MainActivity

4: MembersInjector

在这里我们可以返回到1.中的最后的问题:连接!

终于到这一步了,看到前面参数一层一层传递,初始化了各种的工厂类,等着你一个get()的调用,我就给你初始化好的实例了!还是照样,代码搬上来说话。

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();
  }
}

在这里我还得提示一点就是1.中的这个方法重写里面的调用

 @Override
  public void inject(MainActivity activity) {
    mainActivityMembersInjector.injectMembers(activity);
  }
  • 在这里我们还是先看看已经在1.中初始化了的MainActivity_MembersInjector对象的create()方法干了啥:调用构造方法,并直接返回该工厂类的对象!(这会儿,看看1. 中调用 injectMembers(),或许你会激动点啥的...)
  • 对应的,我们直接找injectMembers()方法,该方法的实现就在这个工厂类里边儿,而且我们有点激动的发现,我们传进来的宿主MainActivity的对象(引用)的属性mainPresenter得到了赋值(初始化!),而等号右边的就是已经准备好了提供Present实例的get()方法!
  • 知道这里可以想到了,Component是连接两头的关键之处

说在最后:本文只是提供一个理解方向,更多的内容本人还在学习当中


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容