接着上一篇: http://blog.csdn.net/niubitianping/article/details/60878104
需要实例的类如果是单例的,需要在Component接口和Module类的方法使用@Singleton。
栗子: 新建一个SingleClass.java
public class SingleClass { //内容可以为空,仅做测试 }在Component接口添加@Singleton注解
@Singleton @Component(modules = LoginModule.class) public interface LoginComponent { void inject(TestActivity activity); }在Module类里面实例SingleClass的方法添加@Singleton注解
@Module public class LoginModule { private Context mContext; //供给LoginStore使用 public LoginModule(Context mContext) { this.mContext = mContext; } @Provides @Singleton //这里添加单例注解 SingleClass provideSingleClass(){ return new SingleClass(); } ...(之前的代码缩略) }测试使用,在TestActivity中@Inject两个Singleclass
public class TestActivity extends Activity { @Inject SingleClass singleClassOne; @Inject SingleClass singleClassTwo; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //DaggerLoginComponent.create().inject(this); //当Module需要构造方法传参的时候,使用builder的方式初始化Dagger。 DaggerLoginComponent.builder() .loginModule(new LoginModule(this)) //loginModule这个方法是构建之后才有的 .build() .inject(this); Log.e("@@", "singleClassOne: "+singleClassOne); Log.e("@@", "singleClassTwo: "+singleClassTwo); } }这时候可以看到输出的两个类的内存地址似乎一样的,证明这是同一个类,即单例类:
03-05 20:53:28.268 30247-30247/com.tpnet.dagger2test E/@@: singleClassOne: com.tpnet.dagger2test.five.SingleClass@c612337 03-05 20:53:28.268 30247-30247/com.tpnet.dagger2test E/@@: singleClassTwo: com.tpnet.dagger2test.five.SingleClass@c612337ps注意: @Singleton 依赖于Component,如果两个不同的Component使用同一个Module来是哟个@Singleton创建单例,将会不是单例。
@Singleton可以看到他的源码为:
@Scope @Documented @Retention(RUNTIME) public @interface Singleton {}这里看到有一个@Scope,这个是用来给依赖划定作用域。
在单例的栗子中,我新建一个TwoActivity和GetInfoComponent,
GetInfoComponent.java
@Singleton @Component(modules = LoginModule.class) public interface GetInfoComponent { void inject(TwoActivity activity); }TwoActivity.java
public class TwoActivity extends Activity { @Inject LoginCtrl loginCtrl; @Inject SingleClass singleClass; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerGetInfoComponent.builder() .loginModule(new LoginModule(this)) .build() .inject(this); Log.e("@@", "TwoActivity: "+singleClass); } }把TestActivity修改为:
可以看到怎么SingleClass这个地址怎么不对呢,不是单例吗?
03-06 14:55:29.556 7020-7020/com.tpnet.dagger2test E/@@: provideLoginCtrlOne被调用: 03-06 14:55:29.556 7020-7020/com.tpnet.dagger2test E/@@: TestActivity: com.tpnet.dagger2test.six.SingleClass@421bd648 03-06 14:55:29.596 7020-7020/com.tpnet.dagger2test E/@@: provideLoginCtrlOne被调用: 03-06 14:55:29.596 7020-7020/com.tpnet.dagger2test E/@@: TwoActivity: com.tpnet.dagger2test.six.SingleClass@421c4558继续看下去
我们的应用有三个范围:
@Singleton: Singleton是Dagger已经定义好的,Application级别的Scope,只要application存活依赖就存活。@UserScope: 只要用户会话是激活状态依赖就存活(在单个应用程序中启动)。重要的是:这个scope存活时间不会超过application本身。每一个新的app实例都会创建一个新的@UserScope(甚至app不同的启动间用户会话没有关闭)。@ActivityScope: Activity范围,依赖于Activity,只要Activity界面存活依赖就存活。例如Activity销毁了,inject的component里面的module里面实例的对象都没了。利用Application级别的单例来实现单例,接下来解决上面的问题:
1. 新建AppModule.java
在这里提供SingleClass类。所以LoginModule里面提供Singleclass的方法需要去掉了。
@Module public class AppModule { @Singleton @Provides SingleClass providerSingleClass(){ return new SingleClass(); } }2. 新建AppComponent.java
@Singleton @Component(modules = AppModule.class) public interface AppComponent { //把AppModule里面的SingleClass桥接出来 SingleClass singleClass(); }3. 自定义Scope
创建一个ActivityScope.java,作为自定义的Scope,用来标识LoginComponent和GetInfoComponent。
@Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope { }4. 添加Component依赖
在LoginComponent和GetInfoComponent添加AppComponent的依赖,并且去掉@Singleton,添加自定义的ActivityScope注解
LoginComponent.java
@ActivityScope @Component(modules = LoginModule.class,dependencies = AppComponent.class) public interface LoginComponent { void inject(TestActivity activity); }GetInfoComponent.java
@ActivityScope @Component(modules = LoginModule.class,dependencies = AppComponent.class) public interface GetInfoComponent { void inject(TwoActivity activity); }5. 创建BaseApplication
完成上面的步骤之后,make 一下module,使得dagger生成DaggerAppComponent。
然后新建一个BaseApplication,用来注入AppComponent:
public class BaseApplication extends Application { AppComponent mAppComponent; @Override public void onCreate() { super.onCreate(); mAppComponent = DaggerAppComponent.create(); } public AppComponent getAppComponent(){ return mAppComponent; } }然后在manifest添加BaseApplication。
6. 在Activity注入
TestActivity的注入改为;
DaggerLoginComponent.builder() .loginModule(new LoginModule(this)) //loginModule这个方法是构建之后才有的 //添加appComponent,参数从BaseApplication获取 .appComponent((((BaseApplication)getApplication()).getAppComponent())) .build() .inject(this);TwoActivity的注入改为:
DaggerGetInfoComponent.builder() .loginModule(new LoginModule(this)) //添加appComponent,参数从BaseApplication获取 .appComponent(((BaseApplication)getApplication()).getAppComponent()) .build() .inject(this);最后运行看到结果,两个Activity里面实例的SingleClass的类相同:
03-06 16:10:29.937 21284-21284/com.tpnet.dagger2test E/@@: provideLoginCtrlOne被调用: 03-06 16:10:29.937 21284-21284/com.tpnet.dagger2test E/@@: TestActivity: com.tpnet.dagger2test.six.SingleClass@421c4530 03-06 16:10:31.438 21284-21284/com.tpnet.dagger2test E/@@: provideLoginCtrlOne被调用: 03-06 16:10:31.438 21284-21284/com.tpnet.dagger2test E/@@: TwoActivity: com.tpnet.dagger2test.six.SingleClass@421c4530自定义Scope可以看看外国大牛的文章: http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/
顾名思义,子@Component。类似@Component的dependencies。 @SubComponent可以在@Component里面进行返回获取。
dependencies不会继承范围,@Subcomponent会。@Subcomponent同时具备两种不同作用域的scope。
来个栗子:
创建SingleClassTwo:
public class SingleClassTwo { //制作演示,可以为空方法 }创建自定义Scope, UserScope.java:
@Scope @Retention(RetentionPolicy.RUNTIME) public @interface UserScope { }创建ChildModule.java
@Module public class ChildModule { @UserScope @Provides SingleClassTwo provideSingleClass(SingleClassOne singleClass){ Log.e("@@", "provideSingleClass: singleClass是否为空:"+ (singleClass == null) ); return new SingleClassTwo(); } }创建ChildComponent.java:
@UserScope //自定义Scope修饰 @Subcomponent(modules = ChildModule.class) public interface ChildComponent { //这里的ThreeActivity在下面创建 void inject(ThreeActivity activity); }ps注意: 如果父的Component使用了@Singleton, 子@Subcomponent 不能使用@Singleton。 就是SubComponent的范围 < 父Component的范围,需要自定义Scope,这里定义了一个UserScope。
创建SingleClassOne:
public class SingleClassOne { //制作演示,可以为空方法 }创建FatherModule.java
@Module public class FatherModule { @Singleton @Provides SingleClassOne providerSingleClass(){ return new SingleClassOne(); } }创建FatherComponent.java:
@Singleton @Component(modules = FatherModule.class) public interface FatherComponent { //父Component可以获取SubComponent ChildComponent getChildComponent(); }上面的代码创建完毕之后,make一下module,然后创建一个ThreeActivity.java
public class ThreeActivity extends Activity{ @Inject SingleClassTwo singleClassTwo; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerOneComponent.create(); } }运行ThreeActivity之后,没看到输出 singleClass是否为空 ,点解?
因为还没有注入ChildComponent,把ThreeActivity的onCreate改为下面的代码:
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerOneComponent.create() .getChildComponent() .inject(this); }即可看到输出:
03-06 18:37:55.216 3414-3414/? E/@@: provideSingleClass: singleClass是否为空:false在上面的栗子中,在ThreeActivity.java的onCreate添加一句代码:
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerFatherComponent.create() .getChildComponent() .inject(this); Log.e("@@", "还没有进行创建singleClassTwo"); }可以看到下面的输出,证明了在inject的时候已经调用了ChildModule的provideSingleClass方法,简单说就是已经实例化了:
03-06 18:48:26.222 14898-14898/? E/@@: provideSingleClass: singleClass是否为空:false 03-06 18:48:26.222 14898-14898/? E/@@: 还没有进行创建singleClassTwo用Lazy标识的变量,在inject的时候并没有实例化,而是在t.get()的时候才实例化并返回。来个栗子:
创建Test.java
public class Test { }创建TestModule.java
@Module public class TestModule { @Provides Test provideTest(){ Log.e("@@", "调用了provideTest方法"); return new Test(); } }创建TestComponent.java
@Component(modules = TestModule.class) public interface TestComponent { void inject(TestActivity activity); }make moudle,然后创建TestActivity.java
public class TestActivity extends Activity{ @Inject Test test; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerTestComponent.builder().build().inject(this); Log.e("@@", "已经注入完成"); } }这时候运行可以看到输出:
03-06 19:09:46.301 5187-5187/com.tpnet.dagger2test E/@@: 调用了provideTest方法 03-06 19:09:46.301 5187-5187/com.tpnet.dagger2test E/@@: 已经注入完成上面的输出这是正常的,现在来修改一下TestActivtiy:
public class TestActivity extends Activity{ // @Inject Test test; @Inject Lazy<Test> test; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerTestComponent.builder().build().inject(this); Log.e("@@", "已经注入完成"); Log.e("@@", "开始第一次get: " + test.get().toString()); Log.e("@@", "开始第二次get: " + test.get().toString()); } }可以看到输出为下面的内容,表示inject的时候还没有进行TestModule里面的provideTest方法,是get的时候才实例化了,而且多次get得到的是同一个Test对象。
03-06 19:14:27.425 9846-9846/com.tpnet.dagger2test E/@@: 已经注入完成 03-06 19:14:27.425 9846-9846/com.tpnet.dagger2test E/@@: 调用了provideTest方法 03-06 19:14:27.425 9846-9846/com.tpnet.dagger2test E/@@: 开始第一次get: com.tpnet.dagger2test.eight.Test@421ae290 03-06 19:14:27.425 9846-9846/com.tpnet.dagger2test E/@@: 开始第二次get: com.tpnet.dagger2test.eight.Test@421ae290使用这个类修饰的变量,也是懒加载,但是它每次get都会重新执行一遍provides实例化的方法。
修改一下上面的TestActivity:
public class TestActivity extends Activity{ // @Inject Test test; //@Inject Lazy<Test> test; @Inject Provider<Test> test; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerTestComponent.builder().build().inject(this); Log.e("@@", "已经注入完成"); Log.e("@@", "开始第一次get: " + test.get().toString()); Log.e("@@", "开始第二次get: " + test.get().toString()); } }可以看到输出为以下,表明了懒加载,每次get都会重新调用provides方法,产生新的对象:
03-06 19:18:09.852 13486-13486/com.tpnet.dagger2test E/@@: 已经注入完成 03-06 19:18:09.852 13486-13486/com.tpnet.dagger2test E/@@: 调用了provideTest方法 03-06 19:18:09.852 13486-13486/com.tpnet.dagger2test E/@@: 开始第一次get: com.tpnet.dagger2test.eight.Test@421af130 03-06 19:18:09.852 13486-13486/com.tpnet.dagger2test E/@@: 调用了provideTest方法 03-06 19:18:09.852 13486-13486/com.tpnet.dagger2test E/@@: 开始第二次get: com.tpnet.dagger2test.eight.Test@421af520Provide不是规定死了每次get都是新的对象。 例如单例,每次get还是同一个对象。在一的栗子的ThreeActivity进行修改:
public class ThreeActivity extends Activity{ //@Inject SingleClassTwo singleClassTwo; @Inject Provider<SingleClassTwo> singleClassTwo; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerFatherComponent.create() .getChildComponent() .inject(this); Log.e("@@", "还没有进行创建singleClassTwo"); Log.e("@@", "get地址1: "+singleClassTwo.get().toString()); Log.e("@@", "get地址2: "+singleClassTwo.get().toString()); } }可以看到输出内容为以下,两次get的对象还是同一个:
03-06 19:22:27.944 17698-17698/? E/@@: 还没有进行创建singleClassTwo 03-06 19:22:27.944 17698-17698/? E/@@: provideSingleClass: singleClass是否为空:false 03-06 19:22:27.944 17698-17698/? E/@@: get地址1: com.tpnet.dagger2test.seven.SingleClassTwo@421b0860 03-06 19:22:27.944 17698-17698/? E/@@: get地址2: com.tpnet.dagger2test.seven.SingleClassTwo@421b0860@Component接口的inject方法接收的参数和传递的参数类型必须一致,不能定义为MainActivty,然后传递Activity,会导致注入失败,对象为空
@Component接口关联的modules中不能有重复的provide类型
@Module类的provide方法使用了Scope,那么对应的@Component接口也必须使用同一个注解。
@Component的dependencies与@Component自身的Scope不能相同。需要自定义Scope
@Singleton的组件不能依赖其他Scope组件,只能其他的Scope组件依赖Singleton组件。
没有Scope的@Component接口不能依赖有Scope的@Component接口
一个@Component接口不能同时有多个@Scope(Subcomponent除外)
@Singleton的生命周期依赖于@Component,@Component的注入类销毁了, @Singleton实例化的类也会没了。
@SubComponent的Scope范围不能大于他的父Component。
懒加载Provider根据@Provides方法实现的不同,get到的对象可能是同一个,可能是不同。
