你所看到较轻松的Dagger2(使用扩展)
来源:互联网 发布:同济启明星软件 编辑:程序博客网 时间:2024/05/22 07:46
之前写了几篇关于dagger2的基础介绍,使用方式以及源码分析,最后准备写一篇关于dagger2的使用扩展.
dagger2提供了很多修饰符
@scope(作用域)
在这里记录我的源码分析结果验证结果,按照上一篇案例我在
@Singletonpublic class DemoPresenter
Presenter类上加上Singleton修饰,然后我们跑一下代码可以看到Inject注入的二个对象的地址一模一样!
现在去掉这个修饰符再跑下看看结果
可以看到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) { }}
简单写下代码
现在MainActivity中二个注入的对象地址一模一样的我们跳转到SecondActivity看下生成对象地址
咦?我特么以为地址会一模一样怎么跳一下界面地址就变了,带着大大的疑问我决定去看看源码?所谓知己知彼百战不殆嘛
@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最坑的地方,让我们误以为加上这个注释就具有单例的能力
我在MainActivity中再生成一次compnoent,前面分析如果
compnoent不变那么compnoent生成的对象就会一直不变,如果它的地址改变了,那么生成的对象地址也会改变。我们看看是不是这样
可以看到第一次注入的二个对象都是第一个compnoent生成的对象是相同的跟我们前面分析的也一致,下一步我们看看第二个compnoent生成的对象
由结果可以看到确实跟我们分析的一样compnoent变了生成的对象地址同样变了!
所以我们加上Singleton注解生成的那段代码我的理解是在compnoent不变的情况下保证compnoent生成的对象永远一样!所以compnoent单例还是需要我们自己做的, Singleton同样需要添加的!
@Qualifier (限定符)
这个注解作用与当我们@provide提供了多个返回相同对象的方法时,dagger懵比了,它并不知道选择哪一个进行返回,这个时候我们用@inject注解就会编译错误
那怎么办呢???这个时候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的扩展使用全部介绍完毕,整个系列算是告一段落~~~
- 你所看到较轻松的Dagger2(使用扩展)
- 你所看到较轻松的Dagger2(使用方式)
- 你所看到较轻松的Dagger2(基础介绍)
- 你所看到较轻松的Dagger2(源码分析)
- 让领导看到你所做的
- 我所理解的Dagger2
- 我所理解的Dagger2
- 公交车所看到的......
- 使用Dagger2前你必须了解的一些设计原则
- 使用Dagger2前你必须了解的一些设计原则
- 使用 Dagger2 前你必须了解的一些设计原则
- 轻松学,听说你还没有搞懂 Dagger2
- Dagger2的使用
- 对Dagger2的使用
- Dagger2的使用
- Dagger2的简单使用
- Dagger2的简单使用
- Dagger2的使用(0):
- hdu 1556 Color the ball
- javascript显示年月日时间代码
- POI导出Excel三
- flv
- EventBus之简单用法
- 你所看到较轻松的Dagger2(使用扩展)
- Android中Handler、Looper、Message、MessageQueue详解
- 【spring】事务管理之声明式事务
- Android对接支付宝移动支付始终无法成功调用H5PayActivity
- 十个商标侵权典型案例 保护知识产权刻不容缓
- 设计模式10-责任链模式
- 走进OpenStack
- LINQ 通过动态生成lambda表达式,实现根据指定属性名称对序列进行排序
- string.Empty与"",null的区别,用哪个更好呢?