你所看到较轻松的Dagger2(使用扩展)

之前写了几篇关于dagger2的基础介绍,使用方式以及源码分析,最后准备写一篇关于dagger2的使用扩展.
dagger2提供了很多修饰符
@scope(作用域)
在这里记录我的源码分析结果验证结果,按照上一篇案例我在

@Singleton
public class DemoPresenter

Presenter类上加上Singleton修饰,然后我们跑一下代码可以看到Inject注入的二个对象的地址一模一样!

QQ截图20170612180852.png

现在去掉这个修饰符再跑下看看结果

QQ截图20170612181028.png

可以看到Singleton是完全有创建单例能力的啊,并且我的Component是在MainActicity中初始化的,现在再创建一个SecondActivity生成对象试试,

public class SecondActivity  extends AppCompatActivity implements BaseView {
    @Inject
    DemoPresenter mDemoPresenter;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);
        DaggerCompnoent.builder().module(new Module(this)).build().inject(this);
        Log.e("wwwSecondDemoPresenter2",mDemoPresenter.toString());
    }

    @Override
    public void setXxx(Person p) {

    }
}

简单写下代码


QQ截图20170612182849.png

现在MainActivity中二个注入的对象地址一模一样的我们跳转到SecondActivity看下生成对象地址

QQ截图20170612183105.png

咦?我特么以为地址会一模一样怎么跳一下界面地址就变了,带着大大的疑问我决定去看看源码?所谓知己知彼百战不殆嘛

 @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.getBaseViewProvider = Module_GetBaseViewFactory.create(builder.module);

    this.demoPresenterProvider =
        DoubleCheck.provider(DemoPresenter_Factory.create(getBaseViewProvider));

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(demoPresenterProvider);

    this.secondActivityMembersInjector =
        SecondActivity_MembersInjector.create(demoPresenterProvider);
  }

这里之前看过源码分析的已经很清楚了就不多说了,
MainActivity_MembersInjector
SecondActivity_MembersInjector
都是一个工厂类里面创建对象,然后inject会调用对象中的injectMembers然后把demoPresenterProvider.get生成的presenter对象注入进去

DoubleCheck.provider(DemoPresenter_Factory.create(getBaseViewProvider));

之前分析的时候好像没有DoubleCheck这个玩意,貌似加了个Singleton就多出个这DoubleCheck.provider( );

点进去看看是什么

  /** Returns a {@link Provider} that caches the value from the given delegate provider. */
  public static <T> Provider<T> provider(Provider<T> delegate) {
    checkNotNull(delegate);
    if (delegate instanceof DoubleCheck) {
      /* This should be a rare case, but if we have a scoped @Bind that delegates to a scoped
       * binding, we shouldn't cache the value again. */
      return delegate;
    }
    return new DoubleCheck<T>(delegate);
  }

里面接收DemoPresenter_Factory对象,把DemoPresenter_Factory传到DoubleCheck构造参数中,然后返回这个对象,我们看看DoubleCheck的get方法做了什么

@SuppressWarnings("unchecked") // cast only happens when result comes from the provider
  @Override
  public T get() {
    Object result = instance;
    if (result == UNINITIALIZED) {
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          instance = result = provider.get();
          /* Null out the reference to the provider. We are never going to need it again, so we
           * can make it eligible for GC. */
          provider = null;
        }
      }
    }
    return (T) result;
  }

其实DoubleCheck就是个代理类,它进行一系列判断后调用DemoPresenter_Factory的get方法生成p对象,
我们前面MainActivity生成的对象一模一样就是因为在MainActivity中
Compnoent只生成一次,而注入对象时调用的就是我们上面分析的代理类DoubleCheck的get()方法,通过分析代码可以知道只要Compnoent对象不变,那么它永远只调用一次get()方法生成一次对象.这里可以解释之前MainActivity生成单例的错觉了,因为我们Compnoent只生成过一次!!!

  @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.mDemoPresenter1 = mDemoPresenter1AndMDemoPresenter2Provider.get();
    instance.mDemoPresenter2 = mDemoPresenter1AndMDemoPresenter2Provider.get();
  }

至于为什么SecondActivity生成的又不一样了,SecondActivity跟MainActivity完全是二个不同对象,生成的Compnoent成员变量自然在二个对象的堆地址中,所以生成的p对象当然不相同了~

这也是Singleton最坑的地方,让我们误以为加上这个注释就具有单例的能力

QQ截图20170612191006.png

我在MainActivity中再生成一次compnoent,前面分析如果
compnoent不变那么compnoent生成的对象就会一直不变,如果它的地址改变了,那么生成的对象地址也会改变。我们看看是不是这样

QQ截图20170612191245.png

可以看到第一次注入的二个对象都是第一个compnoent生成的对象是相同的跟我们前面分析的也一致,下一步我们看看第二个compnoent生成的对象

QQ截图20170612191355.png

由结果可以看到确实跟我们分析的一样compnoent变了生成的对象地址同样变了!
所以我们加上Singleton注解生成的那段代码我的理解是在compnoent不变的情况下保证compnoent生成的对象永远一样!所以compnoent单例还是需要我们自己做的, Singleton同样需要添加的!

@Qualifier (限定符)
这个注解作用与当我们@provide提供了多个返回相同对象的方法时,dagger懵比了,它并不知道选择哪一个进行返回,这个时候我们用@inject注解就会编译错误

QQ截图20170612201335.png

那怎么办呢???这个时候Qualifier就派上用场了

    @Provides
    @Named("name1")
    public DemoPresenter provideDemoPresenter1(){
        return new DemoPresenter(mBaseView);
    }
    @Provides
    @Named("name2")
    public DemoPresenter provideDemoPresenter2(){
        return new DemoPresenter(mBaseView);
    }

比如这段代码中,我提供了二个都返回DemoPresenter对象的方法,我们这个时候需要使用限定符进行标识,@Named是Qualifier 默认实现的一个注解,这里把方法一表示为name1,方法二标识为name2,我们在需要依赖的地方使用

    @Inject
    @Named("name1")
    DemoPresenter mDemoPresenter2;

这样就依赖上方法一返回的对象了~当然你也可以自己自定义一个Qualifier

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {

    /** The name. */
    String value() default "";
}

我们看Named怎么定义的,自定义只需要改变Named命名就可以了

接下来看看Lazy用法,

    @Inject
    Lazy<DemoPresenter> mDemoPresenterLazy;

使用Lazy这个接口注入我们的对象,泛型中存放我们的presenter对象类型,然后运行代码,dagger会帮我们module中生成的p对象存放到我们上面提到过的DoubleCheck类中我们翻下源码

  @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.mDemoPresenterLazy = DoubleCheck.lazy(mDemoPresenterLazyProvider);
  }

继续看看DoubleCheck中lazy方法

  /** Returns a {@link Lazy} that caches the value from the given provider. */
  public static <T> Lazy<T> lazy(Provider<T> provider) {
    if (provider instanceof Lazy) {
      @SuppressWarnings("unchecked")
      final Lazy<T> lazy = (Lazy<T>) provider;
      // Avoids memoizing a value that is already memoized.
      // NOTE: There is a pathological case where Provider<P> may implement Lazy<L>, but P and L
      // are different types using covariant return on get(). Right now this is used with
      // DoubleCheck<T> exclusively, which is implemented such that P and L are always
      // the same, so it will be fine for that case.
      return lazy;
    }
    return new DoubleCheck<T>(checkNotNull(provider));
  }

可以看到返回了一个DoubleCheck对象,

public final class DoubleCheck<T> implements Provider<T>, Lazy<T> 

它实现了Lazy接口,这个时候我们如果调用get方法就会返回p对象,这个过程在上面已经分析了源码过程。

最后再看一个Provider用法

    @Inject
      Provider<DemoPresenter> mDemoPresenterProvider;

这玩意也非常简单,就是把生成p的工厂类对象直接给我们,我们调用get就会调用工厂类的get方法生成p对象

  @Override
  public DemoPresenter get() {
    return Preconditions.checkNotNull(
        module.provideDemoPresenter1(), "Cannot return null from a non-@Nullable @Provides method");
  }

好了dagger的扩展使用全部介绍完毕,整个系列算是告一段落~~~

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

推荐阅读更多精彩内容

  • 部分内容参考自:[Android]使用Dagger 2依赖注入 - DI介绍(翻译)[Android]使用Dagg...
    AItsuki阅读 47,345评论 66 356
  • Dagger2 入门 2016-12-21 更新:添加@Subcomponent注解以及Lazy与Provider...
    fxzou阅读 28,550评论 77 331
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • 梅老师轻声道:江南多竹,我喜欢江南。心霎时柔软起来,好想抱抱她。 我喜欢一切美好的人和事,自然也是喜欢江南,喜欢竹...
    无色生香阅读 1,417评论 18 71