dagger2的文章从寥寥可数到现在的数不胜数,可见其热门程度。
这篇文章主要是记录我对dagger2的理解,从基本使用,到实际运用,由浅入深。以及dagger2的一些变化。
希望大家能取其精华,去其糟粕,谢谢。
目录结构
我想这是许多人的困惑。为什么不直接new一个对象。 而是通过配置各式各样的注解达到new的目的?看了许许多多的文章,都指向一个观点,一切是为了解耦。
比如业务类UserService(UserApi api) . 需要构造这个函数。一开始实例化简单,但是随着业务的跟进你需要保存一些用户设置,构造函数加入SharedPreferences。
随着构造函数的数量不断增加,就会变得越来越累赘,并且又是多人合作,依赖别人写的对象。改起来你说麻烦不(TVT).这就是为什么dagger2适合大型的项目。
如果是小型项目,而且代码都是自己撸的。对于生命周期和使用的对象的依赖关系又比较熟悉,这时可以考虑不使用。当然如果业务类构造函数复杂且需要注入的对象多,不妨可以考虑考虑。
总的来说!对面这样的情况Dagger2维护起来就方便多了,可以使用一个moudule来维护。可以理解为仓库吧。总之就是维护多个仓库。里面提供所需要的实体对象。
直接在声明的时候
@Inject
UserService mUserService;
这时无论UserService 需要依赖多少对象.都ok.会自动去仓库去寻找自己所需要的构造对象。从而达到解耦的目的。
说实话,落后就要挨打。
依赖
compile 'com.google.dagger:dagger:2.12'
annotationProcessor 'com.google.dagger:dagger-compiler:2.12'
先来一个最简单的需求。在activity实例化UserService业务类
通常做法:activity 直接new。
dagger2做法:最简单的注入。需要配合 @inject 与 @Component 注解构成。
不逼逼w(゚Д゚)w。直接 上代码说明
1 业务类。对构造函数进行声明标识,告诉Dagger。生成对象时可以使用这个构造方法。
public class UserService {
@Inject //(1)
UserService() {
}
//假设请求网络数据方法
public void request(){
}
}
2 还需要一个桥梁Component,和activity产生产生关系。
@Component
public interface MainComponent {
//说明要在那个activity注入
void inject(MainActivity mainActivity);
}
3.写好之后进行重构生成注入代码。
重构完后会生成一个DaggerMainComponent,提供注入,名字生成的规则是DaggerXXComponent。
最后在activity使用
public class MainActivity extends AppCompatActivity {
@Inject//(2)要new那个。就inject那个。
UserService mUserService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//(3)注入
DaggerMainComponent.builder().build().inject(this);
Log.w(MainActivity.class.getSimpleName(),mUserService.toString());
mUserService.request();
}
}
说明一下这两个注解的意思:
对构造函数进行声明,Dagger可以构建该类的实例。//(1)
对字段,也就是成员变量声明,就是告诉dagger2 我需要这个实例对象。//(2)
这样就完成一个对象最简单的注入。
当然在实际的项目当中不可能那么简单。如果UserServic需要一个Gson,需要一个Retrofit,一些第三方的对象时,而你需要 @inject声明构造函数。去告诉dagger2要那个对象。在这些情况下是不可行,因为第三方类不能修改。
面对这种情况,就需要@Module注解和@Provides注解来描述依赖关系了。 去解决以上的问题了
需求改变:Userservic 需要一个Gson对象。
业务类的修改,假设UserService需要Gson对象
public class UserService {
Gson gson;
@Inject
public UserService(Gson gson) {
this.gson = gson;
}
public Gson getGson() {
return gson;
}
public void request() {
}
}
这时如果要实例化Gson,按照上面的步骤来说,应该在Gson的构造函数标识@inject。才可以被实例化,由于无法做到,所以就只能声明Module仓库来提供Gson对象。
声明Module
@Module
public class UserModule {
@Provides
Gson provideGson() {
return new Gson();
}
// 如果有了module,可以把Userservic构造函数的@inject去掉.
//依赖对象由module提供。
// 如果没有去掉Userservic的inject并且也在module提供了实例、那么。
//记住,@Module级别高于@Inject。
/* @Provides
UserService providesUserService(Gson gson) {
return new UserService(gson);
}
*/
}
按照惯例,@Provides方法以provide开头,Module类以Module结尾。
修改Component,构建module的关系。
@Component(modules = UserModule.class)//可以有多个modules={xxxModule.class,XXclass,等等}
public interface MainComponent {
void inject(MainActivity mainActivity);
}
最后在重新编译。在activity调用
DaggerMainComponent.builder().userModule(new UserModule()).build().inject(this);
Gson gson = mUserService.getGson();
Log.w(MainActivity.class.getSimpleName(), gson.getClass().toString());
有人会说如果Service需要的对象Context,module要怎么提供?
Userservic
@Inject
public UserService(Gson gson, Context context) {
this.gson = gson;
this.context = context;
}
Module可以通过构造函数去提供实例,并提供出去。
Context mContext;
public UserModule(Context context) {
this.mContext = context;
}
@Provides
Context provideContext(){
return mContext;
}
最后编译,activity调用。
DaggerMainComponent.builder().userModule(new UserModule(this)).build().inject(this);
如果能看懂上面的东西。大概就算是入门了吧。嗯嗯,基本操作。
接下来我们就慢慢扩充我们的需求。慢慢融入到我们的真实项目。
先看一段代码:
UserModule:很简单就提供一个Gson
@Module
public class UserModule {
@Provides
Gson provideGson() {
return new Gson();
}
}
Component
@Component(modules = UserModule.class)
public interface MainComponent {
void inject(MainActivity mainActivity);
}
activity:注入2个Gson.
@Inject
Gson mGson1;
@Inject
Gson mGson2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder().userModule(new UserModule()).build().inject(this);
Log.w("MainActivity", Integer.toHexString(mGson1.hashCode()));
Log.w("MainActivity", Integer.toHexString(mGson2.hashCode()));
}
可以看到这是两个不同的对象
需求:
通常我们在项目中有对象需用频率过高,需要保持全局单例的情况,也就是达到复用的目的。例如全局的Application
,全局的OkHttpClient ,等等….。
通常做法:静态变量,或者单例模式封装,等…
Dagger2:使用@Singleton标识 保持单例,也可以使用自定义scope或者使用Reusable。先说说@Singleton
我们修改一下代码
module
@Provides
@Singleton
Gson provideGson() {
return new Gson();
}
Component
@Singleton
@Component(modules = UserModule.class)
public interface MainComponent {
void inject(MainActivity mainActivity);
}
activity 不改。看看结果
就是那么简单。
注意事项:
别想的太难,仅仅只标记而已,通过这个标记。dagger2获取实例的方法会生成单例。具体的可以看看生成后的源码
module提供对象的方法用@Singleton注解声明,其Component也要保持一致哦。不然会编译不通过。
A activity : Aactivity 注入 。
@inject
Gson gson;
DaggerMainComponent.builder().userModule(new UserModule()).build().inject(this);
B Activity Bactivity 注入 。
@inject
Gson gson;
DaggerMainComponent.builder().userModule(new UserModule()).build().inject(this);
其中A和B的Gson是不可能是同一个对象的,因为初始化的原因。所以要提供整个App的单例就必须保证初始化构建一次。
所有我们可以在自定义Application构建。
public class MyApplication extends Application {
private DaggerMainComponent daggerMainComponent;
@Override
public void onCreate() {
super.onCreate();
//构建
daggerMainComponent= DaggerMainComponent.builder().userModule(new UserModule()).build();
}
public DaggerMainComponent getDaggerMainComponent() {
return daggerMainComponent;
}
}
A activity 和 b activity 使用
MyApplication myApplication = (MyApplication) getApplication();
myApplication.getDaggerMainComponent().inject(this);
这样就可以保持单例,从而达到复用的目的了
有了上面的的基础,我们可以搭建属于我们的第一个模块。
公共模块
让dagger2提供App全局所需要的对象
先搭建我们的公共仓库。
AppModule :最基础的,提供全局的Application 各位看情况而定
@Module
public class AppModule {
Application mApplication;
public AppModule(Application application) {
mApplication = application;
}
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}
@Provides
@Singleton
SharedPreferences providesSharedPreferences(Application application) {
return PreferenceManager.getDefaultSharedPreferences(application);
}
}
NetModule :公共网络请求,使用的是 retrofit2, 根据自己的情况搭建
@Module
public class NetModule {
String mBaseUrl;
// 构造module所需要的参数。根据每个人的情况而定
public NetModule(String baseUrl) {
this.mBaseUrl = baseUrl;
}
@Provides
@Singleton
Cache provideOkHttpCache(Application application) {
int cacheSize = 10 * 1024 * 1024; // 10 MiB
return new Cache(application.getCacheDir(), cacheSize);
}
@Provides
@Singleton
Gson provideGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
@Provides
@Singleton
HttpLoggingInterceptor provideHttpLoggingInterceptor() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return interceptor;
}
@Provides
@Singleton
OkHttpClient provideOkHttpClient(HttpLoggingInterceptor httpLoggingInterceptor,Cache cache) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.cache(cache).
addInterceptor(httpLoggingInterceptor)
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build();
return builder.build();
}
@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient mOkHttpClient) {
return new Retrofit.Builder()
.baseUrl(mBaseUrl)
.client(mOkHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
}
基础的module搭好后,关联 Component
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {
void inject(MyApplication application);
}
最后一步,重新编译。然后使用
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.builder()
.appModule(new AppModule(this))
.netModule(new NetModule("www.github.com"))
.build().inject(this);
}
}
这时候你可能会困惑,你在MyApplication注入用处不大 ,难道要在这里进行网络请求么?当然如果有需要实例化的对象也可以注入。
如果AMainActivity,BMainActivity 需要用到这些公共对象该怎么做?
很简单,在Component关联上不就行了吗?
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {
void inject(MyApplication application);
void inject(AMainActivity activity);
void inject(BMainActivity activity);
}
这样做也行,如果按照上面的这样做,你必须要在 A和B的activity去构建注入才可以获取到这些对象,但是这些对象就不是单例的了。
就忘了最初的考虑。想要保证全局单例,Component只能构建一次,
所以MyApplication 要提供出Component,并且保证构建一次。
修改如下
public class MyApplication extends Application {
private AppComponent mAppComponent;
@Override
public void onCreate() {
super.onCreate();
mAppComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.netModule(new NetModule("www.github.com"))
.build();
}
public AppComponent getAppComponent() {
return mAppComponent;
}
}
AMainActivity
@Inject
Retrofit mRetrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((MyApplication)getApplication()).getAppComponent().inject(this);
Log.w("AMainActivity", mRetrofit.toString());
findViewById(R.id.tv_text2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(AMainActivity.this,BMainActivity.class));
}
});
}
BMainActivity
@Inject
Retrofit mRetrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((MyApplication)getApplication()).getAppComponent().inject(this);
Log.w("BMainActivity", mRetrofit.toString());
//((MyApplication)getApplication()).getAppComponent().inject();
}
这样就保证了
虽然这样可以保证全局的唯一性。但是随着activity的增多,可能每个activity用到的module都不一样,也就是需要注入的对象不同。
@Singleton
@Component(modules = {AppModule.class, NetModule.class,BModule.class,AModule.class,XModule.class,.....Module.class})
public interface AppComponent {
void inject(MyApplication application);
void inject(AMainActivity activity);
void inject(BMainActivity activity);
void inject(XMainActivity activity);
......
}
一个Component堆多了module看着也不舒服。就像整个项目没有BaseActivity一样.你觉得合理么?
所以下面介绍一下Component dependencies ,和自定义Scope。
很简单,直接看代码。
假设我们AMainActivity 需要Amodule 提供业务对象。各位根据实际情况而定
@Module
public class AModule {
@Provides
UserService providesUserService(){
return new UserService();
}
}
我们新建一个ActivityComponent 统筹所有的Activity.
@Component(modules = {AModule.class}, dependencies = AppComponent.class)//可以依赖多个Component
public interface ActivityComponent {
void inject(AMainActivity aMainActivity);
}
注意:
可以看到 我们的 Component 加上了dependencies 并且继承与AppComponent。
这时候要注意了。如果现在进行编译的话会编译不通过。
这里有个规则。
如果依赖的Component需要用到父Component的对象,必须要父Component通过方法提供出来。
所以, AppComponent 修改如下
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {
//暴露出子Component 需要的对象。各位根据直接的情况而定。
//gson
Gson gson();
Application application();
OkHttpClient okHttpClient();
SharedPreferences sharedPreferences();
Retrofit retrofit();
void inject(MyApplication application);
void inject(BMainActivity bMainActivity);
}
这时候在编译就会出现以下问题。
大概的意思是没有scope的不能依赖有scope的组件,也就是说你的Component要有一个Scope修饰
然后你在ActivityComponent 加上@Singleton标识还是上面那个提示。
这时候注意了。
@Component的dependencies与@Component自身的scope不能相同。
可以通过自定义Scope来解决上面的问题,这算是自定义Scope的场景使用之一。
在看别人的项目的时候通常会看到两个Scope,ActivityScope 跟 FragmentSopce。 (也有可能其他命名。随意)
如其字义,好理解,使用于Activity和fragment。
废话不多说,直接仿写 @Singleton。
ActivityScope
@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScope {}
FragmentScope 和上面的一样,改个名字即可。
然后在我们的ActivityComponent修改如下
@ActivityScope
@Component(modules = {AModule.class}, dependencies = AppComponent.class)
public interface ActivityComponent {
void inject(AMainActivity aMainActivity);
}
当然,如果想依赖的Module也希望提供单例的话,这时也可以加上@ActivityScope即可
@Module
public class AModule {
@Provides
@ActivityScope
UserService providesUserService(){
return new UserService();
}
}
最后编译即可。
AMainActivitty
//((MyApplication)getApplication()).getAppComponent().inject(this);
DaggerActivityComponent.builder().appComponent(((MyApplication)getApplication()).getAppComponent())
.build().inject(this);
如果是在fragment里使用呢?和上面几乎没啥区别
@FragmentScope
@Component(modules = XXModule.class,....XXModule.class, dependencies = AppComponent.class)
public interface FragmentComponent {
void inject(XXFragment fragment);
// .....inject...
}
最后编译使用即可。
也许上面所搭建方式的会与其他人的有所不同。
有些人是 一个模块 对应着一个Component和module。
在github上随便找的项目截图
activity
fragment
项目dagger2结构
这样做也行,但是会写比较多的 Component和module。
我就是懒一点。直接2个Component统筹全局。当然,这不是重点。
重要的是怎么理解这些知识点。正所谓万变不离其宗。
项目的基本搭建就到此结束了。接下来是一些优化和其他相关注解。
我们可以看到上面搭建的module。如果需要特定的参数,有种方法是通过构造函数进行注入。
比如上面的NetModule
// 构造module所需要的参数。根据每个人的情况而定
public NetModule(String baseUrl) {
this.mBaseUrl = baseUrl;
}
也可以通过Component来提供,清晰。
我们就拿上面所写的两个module作为例子修改。优化
新建AppModule2
@Module
public class AppModule2 {
/*
由于要改为由Component提供参数,所以这里注释掉
Application mApplication;
public AppModule2(Application application) {
mApplication = application;
}
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}*/
@Provides
@Singleton
SharedPreferences providesSharedPreferences(Application application) {
return PreferenceManager.getDefaultSharedPreferences(application);
}
}
NetModule2
@Module
public class NetModule2 {
/*
改为由Component提供!
String mBaseUrl;
// 构造module所需要的参数。根据每个人的情况而定
public NetModule2(String baseUrl) {
this.mBaseUrl = baseUrl;
}*/
//.. 省略
//把mBaseUrl 作为参数传入
@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient mOkHttpClient,String mBaseUrl) {
return new Retrofit.Builder()
.baseUrl(mBaseUrl)
.client(mOkHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
}
最后Component
@Singleton
@Component(modules = {AppModule2.class, NetModule2.class})
public interface AppComponent2 {
@Component.Builder
interface Builder {
// Module所需要的参数可以这样提供
@BindsInstance
Builder application(Application application);
@BindsInstance
Builder baseUrl(String baseUrl);
AppComponent2 build();
}
//gson
Gson gson();
Application application();
OkHttpClient okHttpClient();
SharedPreferences sharedPreferences();
Retrofit retrofit();
void inject(MyApplication application);
void inject(BMainActivity bMainActivity);
}
使用
DaggerAppComponent2.builder().application(this).baseUrl("https://api.xxx.com/").build().inject(this);
在上面我们使用到了Singleton 和 自定义了 activityScope 和 fragmentScope。定义他们的原因可以复用对象,并且可以保证局部单例。
假如你仅仅是需要缓存依赖的实例,达到复用的效果。且不需要那么多的scope约束。可以考虑用这个替换。
Reusable 作用域不关心绑定的 Component,只需要标记目标类或 provide 方法即可。
项目作用域优化,重新修改一下module
AppModule2
@Module
public class AppModule2 {
@Provides
@Reusable //替换原来Scope
SharedPreferences providesSharedPreferences(Application application) {
return PreferenceManager.getDefaultSharedPreferences(application);
}
}
NetModule2(略)
意思和上面一样,替换即可。
Component 把Scope删除即可
@Component(modules = {AppModule2.class, NetModule2.class})
public interface AppComponent2 {
@Component.Builder
interface Builder {
// Module所需要的参数可以这样提供
@BindsInstance
Builder application(Application application);
@BindsInstance
Builder baseUrl(String baseUrl);
AppComponent2 build();
}
//gson
Gson gson();
Application application();
OkHttpClient okHttpClient();
SharedPreferences sharedPreferences();
Retrofit retrofit();
void inject(MyApplication application);
}
子Component,一样Scope删除即可,这里的依赖module各位自己定。
@Component( dependencies = AppComponent2.class)
public interface ActivityComponent2 {
void inject(Di2Activity di2Activity);
void inject(Di2Activity2 di2Activity);
}
在MyApplication 提供ActivityComponent2实例。
private AppComponent2 mAppComponent2;
@Override
public void onCreate() {
super.onCreate();
mAppComponent2 = DaggerAppComponent2.builder().application(this).baseUrl("https://api.xxx.com/").build();
}
public AppComponent2 getAppComponent2() {
return mAppComponent2;
}
然后 使用测试打印
Di2Activity
@Inject
Retrofit mRetrofit;
MyApplication myApplication = (MyApplication) getApplication();
DaggerActivityComponent2.builder().appComponent2(myApplication.getAppComponent2()).build().inject(this);
Log.w("Di2Activity",mRetrofit.toString());
Di2Activity2
@Inject
Retrofit mRetrofit;
MyApplication myApplication = (MyApplication) getApplication();
DaggerActivityComponent2.builder().appComponent2(myApplication.getAppComponent2()).build().inject(this);
Log.w("Di2Activity2",mRetrofit.toString());
查看结果
这样就保证了对象的复用了
为什么会出现这个扩展库呢?英文好大的大兄弟可以去看官网的介绍Dagger.android。
不好的话 那只能看我吹牛逼 简单的翻译了。
如果fagment 和activity 要用到对象就不得不使用Dagger依赖注入实例。
public class FrombulationActivity extends Activity {
@Inject Frombulator frombulator;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO THIS FIRST. Otherwise frombulator might be null!
((SomeApplicationBaseType) getContext().getApplicationContext())
.getApplicationComponent()
.newActivityComponentBuilder()
.activity(this)
.build()
.inject(this);
// ... now you can write the exciting code
}
}
如果每新建一个Activity 或者fragment 都要写一次,谁都想吐.
还有专业的原因:是它打破了依赖注入的核心原则:一个类不应该知道如何实现依赖注入。
对我来说这个扩展库就是解决这个问题的。就是要达到注入一次,其他地方就不用理。
添加扩展库
compile 'com.google.dagger:dagger-android-support:2.12'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.12'
我们抛弃上面所写的 子Component(ActivityComponent2) 采用新的方式
新建ActivityBindingModule 管理所有的Activity
@Module
public interface ActivityBindingModule {
//Di2Activity3 需要的特定 module 可以在这里添加
@ContributesAndroidInjector(modules = DiModule.class)
Di2Activity3 di3ActivityInjector();
@ContributesAndroidInjector
Di2Activity4 di4ActivityInjector();
//...省略
}
DiModule 提供一个业务类
@Module
public class DiModule {
@Provides
@Reusable
DouBanService provideUserservice(Retrofit r){
return new DouBanService(r);
}
}
public class DouBanService {
private Retrofit mRetrofit;
public DouBanService(Retrofit mRetrofit) {
this.mRetrofit = mRetrofit;
}
public void request() {
DouBanApi douBanApi = mRetrofit.create(DouBanApi.class);
douBanApi.getBook().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer() {
@Override
public void accept(Book book) throws Exception {
Log.w("DouBanService", book.toString());
}
});
}
}
修改 component
@Component(modules = {
AppModule2.class,
NetModule2.class,
ActivityBindingModule.class,
AndroidSupportInjectionModule.class
})
public interface AppComponent2 extends AndroidInjector<MyApplication2> {
@Component.Builder
interface Builder {
// Module所需要的参数可以这样提供
@BindsInstance
Builder application(Application application);
@BindsInstance
Builder baseUrl(String baseUrl);
AppComponent2 build();
}
//gson
Gson gson();
Application application();
OkHttpClient okHttpClient();
SharedPreferences sharedPreferences();
Retrofit retrofit();
void inject(MyApplication application);
}
MyApplication2
public class MyApplication2 extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector dispatchingActivityInjector;
@Override
public void onCreate() {
super.onCreate();
DaggerAppComponent2.builder().baseUrl("https://api.douban.com/").application(this).build().inject(this);
}
@Override
public AndroidInjector activityInjector() {
return dispatchingActivityInjector;
}
}
最后新建一个BaseActivity
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//统一注入,要在super之前。
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(layout());
init();
}
protected abstract void init();
@LayoutRes
protected abstract int layout();
}
然后让Activity继承BaseActivity.直接使用即可
public class Di2Activity3 extends BaseActivity {
@Inject
Retrofit mRetrofit;
@Inject
DouBanService mDouBanService;
@Override
protected void init() {
Log.w("Di2Activity2",mRetrofit.toString());
findViewById(R.id.tv_text2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(Di2Activity3.this,Di2Activity4.class));
}
});
mDouBanService.request();
}
@Override
protected int layout() {
return R.layout.activity_main;
}
}
fragment中怎么使用 和 源码就不分析了。可以参考下,下面几位大兄弟的文章
Dagger 2应用于Android的完美扩展库-dagger.android
告别Dagger2模板代码:DaggerAndroid原理解析
顺便可以参考一下googlesamples中,dagger的使用实战。
googlesamples todo-mvp-dagger
这两个注解都是同一个意思。就是当你的module提供了同一个对象。然而在使用的时候dagger2不知道用那个。
限定符为依赖分别打上标记,指定提供某个依赖
@Named
@Module
public class UserModule {
@Provides
@Singleton
@Named("Book1")
Book provideBook1() {
Book book = new Book();
book.setTitle("语文");
return book;
}
@Provides
@Singleton
Book provideBook2() {
Book book = new Book();
book.setTitle("数学");
return book;
}
}
比如我要上面语文的对象
activity
@Inject
@Named("Book1")
Book mBook;
在module中比如要语文的对象
@Provides
@Singleton
String provideBook(@Named("Book1")Book book) {
return book.getTitle();
}
@Qualifier
和上面的一个Scope一个鸟样。自定义@Qualifier
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BookQualifier {}
然后module
@Provides
@Singleton
@BookQualifier
Book provideBook2() {
Book book = new Book();
book.setTitle("数学");
return book;
}
使用
activity
@Inject
@BookQualifier
Book mBook2;
module
@Provides
@Singleton
String provideBook(@BookQualifier Book book) {
return book.getTitle();
}
完成
就是想在使用时再完成初始化,加快速度。
activity
@Inject
Lazy mGson3;
//在想要使用的地方
Gson gson = lazyCar.get();
只有在调用 Lazy 的 get() 方法时才会初始化依赖实例注入依赖。
SubComponent被称为是子component,和上面的Component dependencies 有异曲同工之处。
而我们在上面说道。如果另一个Component要复用父component中的对象。
其父Component就要通过方法暴露出来。
而subComponent 就不需要。
我们修改下上面的例子
AppComponentSub
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponentSub {
/*//gson
//子Component 继承关系中不用显式地提供暴露依赖实例的接口
Gson gson();
Application application();
OkHttpClient okHttpClient();
SharedPreferences sharedPreferences();
Retrofit retrofit();*/
//声明子Component是谁,表明 ActivityComponentSub 继承 AppComponentSub
ActivityComponentSub activityComponentSub();
void inject(MyApplication application);
}
ActivityComponentSub
@ActivityScope
@Subcomponent(modules = {AModule.class})
public interface ActivityComponentSub {
void inject(AMainActivity aMainActivity);
}
MyApplication 构建并提供 AppComponentSub
public class MyApplication extends Application {
//子SubComponent继承方式
private AppComponentSub mAppComponentSub;
@Override
public void onCreate() {
super.onCreate();
mAppComponentSub = DaggerAppComponentSub.builder().appModule(new AppModule(this))
.netModule(new NetModule("https://api.douban.com/"))
.build();
}
}
public AppComponentSub getAppComponentSub() {
return mAppComponentSub;
}
使用
AMainActivity
@Inject
UserService mUserService;
MyApplication myApplication = (MyApplication)getApplication();
myApplication.getAppComponentSub().activityComponentSub().inject(this);
Log.w("AMainActivity", mUserService.toString());
可以看下这大兄弟的详情文章。说的很详细
Dagger 2 完全解析(三),Component 的组织关系与 SubComponent
如果能看到这里的都是真爱
还是那句话。取其精华,去其糟粕
Dagger2demo