Dagger系列:
- Dagger 2从浅到深(一)
- Dagger 2从浅到深(二)
- Dagger 2从浅到深(三)
- Dagger 2从浅到深(四)
- Dagger 2从浅到深(五)
- Dagger 2从浅到深(六)
- Dagger 2从浅到深(七)
- Dagger 2应用于Android的完美扩展库-dagger.android
Demo地址:
总所周知的是,Android的内存是十分昂贵的,所以,能省就省。这也造成了,有时候想延迟实例化对象,在需要的时候,才会进行实例化。就像冰箱里的水果一样,等我想吃的时候,才会拿出来,保证它的新鲜度。
又有时候,注入的是实例的列表,而不是单个实例的值。如果列表少,还可以重复调用@Inject注入实例。如果列表说在几十甚至上百时,也重复调用@Inject么?感觉有点繁琐哦。
Lay<T>和Provider<T>,不由自主的进入的我们的视线,它又给我们带来什么样的惊喜呢!!!
Lazy<T>
对于任何绑定的对象T,当你想惰性实例化它时,都可以创建一个延迟实例化的Lazy<T>。当你需要它时,调用get()方法时,就会实例化对象。
public class BananaBean {
@Inject
public BananaBean() {
Log.d("test", "BananaBean()");
}
}
public class FruitActivity extends AppCompatActivity {
***
@Inject
Lazy<BananaBean> mBananaBeanLazy;
@Override
protected void onCreate(Bundle savedInstanceState) {
***
BananaBean beanA = mBananaBeanLazy.get();
// advanced.todo.com.daggerlearn.bean.BananaBean@3d061bc6
Log.d("test", beanA.toString());
BananaBean beanB = mBananaBeanLazy.get();
// advanced.todo.com.daggerlearn.bean.BananaBean@3d061bc6
Log.d("test", beanB.toString());
}
***
}
现惰性注入了BananaBean的两个实例 - beanA和beanB,看它们的内存地址是一样的。另一方面,BananaBean的构造函数只有在创建beanA,也就是第一次调用get()方法时调用了一次。也就是说,Lazy只有第一次调用get()方法时,调用构造函数实例化对象,然后将该对象缓存。以后再调用get()方法时,都会返回缓存的实例,并且不会再调用构造函数,创建实例。
注意:
- 如果T是单例,那么Lazy<T>将是ObjectGraph内所有注入的实例;否则,每个注入点将创建自己的Lazy<T>实例。
- 无论如何,对任何给定的Lazy<T>实例的调用将返回相同的底层实例.
Provider<T>
有时您需要注入多个实例列表,而不是仅注入单个值。此时,有多种选择,比如工厂模式、Builder模式等。当然,你还有另外一种选择,那就是选择注入一个Provider <T>,而不只是T。
当Provider<T> 每次调用get()方法时,都会执行绑定逻辑并创建一个实例。
现有类BananaBean,其构造函数被@Inject注解。在FruitActivity类中,注入了Provider实例,然后调用其get()方法,创建BananaBean实例。
public class BananaBean {
@Inject
public BananaBean() {
Log.d("test", "BananaBean()");
}
}
public class FruitActivity extends AppCompatActivity {
***
@Inject
Provider<BananaBean> mBananaBeanProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
***
BananaBean beanA = mBananaBeanProvider.get();
BananaBean beanB = mBananaBeanProvider.get();
// advanced.todo.com.daggerlearn.bean.BananaBean@3d061bc6
Log.d("test", beanA.toString());
// advanced.todo.com.daggerlearn.bean.BananaBean@3d061bc6
Log.d("test", beanB.toString());
}
***
}
从Log打印中,我们可以清晰看出来,每次调用get()方法,都会调用BananaBean的构造函数,实例化一个新的对象,而不像Lazy<T>那样将第一次创建的实例缓存。
这时,会有一个疑问,我们所知道的是,BananaBean被@Scope注解时,在Scope作用范围内,只有第一次注入时,调用构建函数,创建一个新的实例对象,然后将该对象缓存,后续的注入实例都是调用该缓存。Provder<T>中的T,被Scope注解时,会怎么样呢?下面,我们修改下BananaBean类,用@TodoScope注解它,但是FruitActivity不做任何修改。我们看mBananaBeanProvider调用get()方法时的效果:
@TodoScope
public class BananaBean {
@Inject
public BananaBean() {
Log.d("test", "BananaBean()");
}
}
public class FruitActivity extends AppCompatActivity {
***
@Inject
Provider<BananaBean> mBananaBeanProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
***
BananaBean beanA = mBananaBeanProvider.get();
BananaBean beanB = mBananaBeanProvider.get();
// advanced.todo.com.daggerlearn.bean.BananaBean@3d061bc6
Log.d("test", beanA.toString());
// advanced.todo.com.daggerlearn.bean.BananaBean@3d061bc6
Log.d("test", beanB.toString());
}
***
}
此时,在两次调用mBananaBeanProvider的get()方法时:
- BananaBean的构造函数被调用了一次
- beanA和beanB的内存一致
我们可以这么认为,尽管是Provider<T>提供注入的对象,但@Scope注解的功能依然存在。
其中,官方对Provider<T>的解释是:Provider<T>将通过get()方法提供T实例,通常是由注入器来实现。从Dagger 2从浅到深(四),我们已经了解到,Scope注解作用的核心是对注入器的控制,那么出现这样的效果,也就不足为奇了。