对于@Scope
注解,不少同窗都疑惑,今天咱们就来了解一下@Scope
相关的知识,这里将会分为两部分介绍:java
Component
状况下@Scope
的做用Component
状况下对于@Scope
的限制首先,咱们须要了解@Scope
实际上是一个 元注解,它和咱们在 Dagger2 知识梳理(2) - @Qulifier 和 @Named 解决依赖注入迷失 一文中介绍的@Qualifier
同样,是用于 描述注解的注解,关于元注解更多的知识能够参考以前的这篇文章 Java&Android 基础知识梳理(1) - 注解。git
@Scope
所描述的注解用于两个地方:github
Component
类Module
中用于建立实例的provideXXX
方法而咱们常常看见的@Singleton
注解其实就是用@Scope
描述的注解,虽然它的表面意思是“单例”,可是咱们后面会看到它和单例其实并无必然的关系。ide
@Scope
描述的注解相似于下面这样,这里的PerScopeActivity
就是用@Scope
描述的注解:ui
@Documented
@Retention(RUNTIME)
@Scope
public @interface PerScopeActivity {}
复制代码
有可能会用到该注解的有两个地方:this
Component
类@Component(dependencies = {ScopeAppComponent.class}, modules = {ScopeActivityModule.class})
@PerScopeActivity
public interface ScopeActivityComponent {
public void inject(ScopeActivity scopeActivity);
ScopeFragmentComponent scopeFragmentComponent();
}
复制代码
Module
中用于建立实例的provideXXX
方法@Module
public class ScopeActivityModule {
@Provides
@PerScopeActivity
public ScopeActivitySharedData provideScopeActivityData() {
return new ScopeActivitySharedData();
}
@Provides
public ScopeActivityNormalData provideScopeActivityNormalData() {
return new ScopeActivityNormalData();
}
}
复制代码
在单个Component
状况下使用@Scope
有如下几点说明:spa
Module
的provideXXX
方法上加上了@Scope
声明,那么在与他关联的Component
上也必须加上相同的@Scope
声明
Component
加上了@Scope
声明,provideXXX
,那么和Component
不加声明的状况相同。Module
的provideXXX
方法和Component
都加上了@Scope
声明,那么在Component
实例的生命周期内,只会建立一个由provideXXX
方法返回的实例。也就是说,该Component
会持有以前经过provideXXX
方法建立的实例的引用,若是以前建立过,那么就再也不调用Module
的provideXXX
去建立新的实例,而是直接返回它以前持有的那一份。上面的例子中,咱们经过ScopeActivityModule
建立了两种类型的数据,provideScopeActivityData()
方法上加上了@PerScopeActivity
,而提供ScopeActivityNormalData
的provideScopeActivityNormalData()
方法则没有,后面咱们将会看到,若是在目标类中使用同一个ScopeActivityComponent
注入,而有多个ScopeActivitySharedData
变量的状况下它们指向的是同一块内存地址,而ScopeActivityNormalData
则会指向不一样的内存地址。3d
对于单个Component
还比较好理解,可是在组织多个Component
的状况下就有些复杂了,这里的“组织”就是咱们在前一篇 Dagger2 知识梳理(3) - 使用 dependencies 和 @SubComponent 完成依赖注入 谈到的 依赖方式 和 继承方式。code
Component
声明了@Scope
,那么其它的Component
也须要声明。Component
和须要依赖的Component
的@Scope
不能相同
Component
的@Scope
不能够为@Singleton
。
Component
的@Scope
不能够和父Component
的@Scope
相同:
Component
的@Scope
不为@Singleton
,那么子Component
的@Scope
能够为@Singleton
。这些限制是由Dagger2
在编译时去检查的,其目的是保证使用者不要对@Scope
产生滥用的现象,由于@Scope
的目的是 在特定做用域内控制被注入实例的复用。component
为了让你们更好的验证上面关于@Scope
的解释,下面用一个Demo
来演示,完整代码能够从 Dagger2Sample 的第四章获取,这个Demo
包括三个大部分:
对应于咱们平时的Application
类,并提供了全局的ScopeAppData
类,在其ScopeAppComponent
上有@Singleton
注解。
@Singleton
@Component(modules = {ScopeAppModule.class})
public interface ScopeAppComponent {
public ScopeAppData getScopeAppData(); //若是它被其它的Component依赖,那么须要声明getXXX方法。
}
复制代码
@Module
public class ScopeAppModule {
@Provides
@Singleton
public ScopeAppData provideScopeAppData() {
return new ScopeAppData();
}
}
复制代码
对应于一个主页面,其内部包含了ScopeActivitySharedData
和ScopeActivityNormalData
,前者在ScopeActivityComponent
的生命周期内保持惟一性,并带有PerScopeActivity
注解。
@Component(dependencies = {ScopeAppComponent.class}, modules = {ScopeActivityModule.class})
@PerScopeActivity
public interface ScopeActivityComponent {
public void inject(ScopeActivity scopeActivity);
ScopeFragmentComponent scopeFragmentComponent();
}
复制代码
@Module
public class ScopeActivityModule {
@Provides
@PerScopeActivity
public ScopeActivitySharedData provideScopeActivityData() {
return new ScopeActivitySharedData();
}
@Provides
public ScopeActivityNormalData provideScopeActivityNormalData() {
return new ScopeActivityNormalData();
}
}
复制代码
对于于Activity
下的一个子界面,它和ScopeActivityComponent
是继承关系,并带有@PerScopeFragment
注解:
@Subcomponent(modules = {ScopeFragmentModule.class})
@PerScopeFragment
public interface ScopeFragmentComponent {
public void inject(ScopeFragment scopeFragment);
}
复制代码
@Module
public class ScopeFragmentModule {
@Provides
@PerScopeFragment
public ScopeFragmentData provideScopeFragmentData() {
return new ScopeFragmentData();
}
}
复制代码
以上三个部分的关系为:
ScopeActivityComponent
依赖于ScopeAppComponent
ScopeFragmentComponent
继承于ScopeActivityComponent
Module
上都有用@Scope
描述的注解:@Singleton
、@PerScopeActivity
,@PerScopeFragment
。经过这个例子能够覆盖到上面咱们介绍的全部场景,你们能够直接在Github
上查看,也能够clone
下来,进行修改验证。
在Activity
和Fragment
中,咱们打印出变量的地址来验证前面的结论:
App
public class ScopeApp extends Application {
private ScopeAppComponent mScopeAppComponent;
@Override
public void onCreate() {
super.onCreate();
mScopeAppComponent = DaggerScopeAppComponent.builder().scopeAppModule(new ScopeAppModule()).build();
}
public ScopeAppComponent getAppComponent() {
return mScopeAppComponent;
}
}
复制代码
Activity
类public class ScopeActivity extends AppCompatActivity {
private static final String TAG = ScopeActivity.class.getSimpleName();
private ScopeActivityComponent mScopeActivityComponent;
@Inject
ScopeAppData mScopeAppData;
@Inject
ScopeActivitySharedData mScopeActivitySharedData1;
@Inject
ScopeActivitySharedData mScopeActivitySharedData2;
@Inject
ScopeActivityNormalData mScopeActivityNormalData1;
@Inject
ScopeActivityNormalData mScopeActivityNormalData2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scope);
getScopeActivityComponent().inject(this);
TextView tvData = (TextView) findViewById(R.id.tv_scope_activity);
String result = "[ScopeActivity Space] \n mScopeAppData=" + mScopeAppData
+ "\n\n" + "mScopeActivitySharedData1=" + mScopeActivitySharedData1
+ "\n\n" + "mScopeActivitySharedData2=" + mScopeActivitySharedData2
+ "\n\n" + "mScopeActivityNormalData1=" + mScopeActivityNormalData1
+ "\n\n" + "mScopeActivityNormalData2=" + mScopeActivityNormalData2;
tvData.setText(result);
}
public ScopeActivityComponent getScopeActivityComponent() {
if (mScopeActivityComponent == null) {
ScopeAppComponent scopeAppComponent = ((ScopeApp) getApplication()).getAppComponent();
mScopeActivityComponent = DaggerScopeActivityComponent.builder().scopeAppComponent(scopeAppComponent).build();
}
return mScopeActivityComponent;
}
}
复制代码
Fragment
类public class ScopeFragment extends Fragment {
private ScopeActivity mScopeActivity;
@Inject
ScopeAppData mScopeAppData;
@Inject
ScopeActivitySharedData mScopeActivitySharedData;
@Inject
ScopeActivityNormalData ScopeActivityNormalData;
@Inject
ScopeFragmentData mScopeFragmentData;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mScopeActivity = (ScopeActivity) context;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_scope, container, false);
mScopeActivity.getScopeActivityComponent().scopeFragmentComponent().inject(this);
TextView tv = (TextView) rootView.findViewById(R.id.tv_scope_fragment);
String result = "[ScopeFragment Space] \n mScopeAppData=" + mScopeAppData
+ "\n\n" + "mScopeActivitySharedData1=" + mScopeActivitySharedData
+ "\n\n" + "ScopeActivityNormalData=" + ScopeActivityNormalData
+ "\n\n" + "mScopeFragmentData=" + mScopeFragmentData;
tv.setText(result);
return rootView;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
复制代码
结果为:
ScopeAppData
:该数据是由ScopeAppModule
提供的,而它加上了@Singleton
注解,而且咱们调用的是同一个对象,所以在Activity
和Fragment
中地址相同。ScopeActivitySharedData
:在它的provide
方法上,咱们加上了@PerScopeActivity
注解,所以在Activity
和Fragment
中,它的地址相同。ScopeActivityNormalData
:虽然在提供它的ScopeActivityModule
中加上了@PerScopeActivity
注解,可是在provide
方法上没有声明,所以不管是在Activity
,仍是在Fragment
中,都是指向不一样的地址。ScopeFragmentData
:用于演示如何经过继承的方式,来实现依赖注入。