Dagger2的入坑指南[捂脸][详]!!

2024-02-07 08:10
文章标签 指南 dagger2 捂脸

本文主要是介绍Dagger2的入坑指南[捂脸][详]!!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

 dagger2的文章从寥寥可数到现在的数不胜数,可见其热门程度。

这篇文章主要是记录我对dagger2的理解,从基本使用,到实际运用,由浅入深。以及dagger2的一些变化。

希望大家能取其精华,去其糟粕,谢谢。

目录结构

    • 前言
    • 为什么要使用dagger2
      • 从需求的角度
      • 从开发者的角度
    • 基本的使用
      • inject
      • Component
      • Module
      • Provides
      • 基本使用总结
    • 循循渐进的项目搭建
      • Singleton
      • Component dependencies
      • 自定义Scope
    • 项目搭建优化
      • Binding Instances 构建方式
      • Reusable Scope 作用域
      • 扩展库daggeradnroid
    • 其他注解
      • Qualifier和Named
      • Lazy 延迟注入
      • SubComponent
    • 总结


为什么要使用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;@Overrideprotected 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();     }
}

说明一下这两个注解的意思:

@inject

  1. 对构造函数进行声明,Dagger可以构建该类的实例。//(1)

  2. 对字段,也就是成员变量声明,就是告诉dagger2 我需要这个实例对象。//(2)

@Component

  • 可以理解为桥梁,就是将它们联系起来。

 这样就完成一个对象最简单的注入。

 当然在实际的项目当中不可能那么简单。如果UserServic需要一个Gson,需要一个Retrofit,一些第三方的对象时,而你需要 @inject声明构造函数。去告诉dagger2要那个对象。在这些情况下是不可行,因为第三方类不能修改。

  面对这种情况,就需要@Module注解和@Provides注解来描述依赖关系了。 去解决以上的问题了


需求改变:Userservic 需要一个Gson对象。

这里写图片描述

业务类的修改,假设UserService需要Gson对象

public class UserService {Gson gson;@Injectpublic UserService(Gson gson) {this.gson = gson;}public Gson getGson() {return gson;}public void request() {}}

这时如果要实例化Gson,按照上面的步骤来说,应该在Gson的构造函数标识@inject。才可以被实例化,由于无法做到,所以就只能声明Module仓库来提供Gson对象。

声明Module

@Module
public class UserModule {@ProvidesGson provideGson() {return new Gson();}// 如果有了module,可以把Userservic构造函数的@inject去掉.//依赖对象由module提供。// 如果没有去掉Userservic的inject并且也在module提供了实例、那么。//记住,@Module级别高于@Inject。/*    @ProvidesUserService providesUserService(Gson gson) {return new UserService(gson);}
*/
}

@Module

  • 注解的类表明它可以提供依赖对象,声明这是一个仓库。标识可以提供对象

@Provides

  • 告诉Dagger我们想要构造对象并提供这些依赖

按照惯例,@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

 @Injectpublic UserService(Gson gson, Context context) {this.gson = gson;this.context = context;}

Module可以通过构造函数去提供实例,并提供出去。

  Context mContext;public UserModule(Context context) {this.mContext = context;}@ProvidesContext provideContext(){return mContext;}

最后编译,activity调用。

        DaggerMainComponent.builder().userModule(new UserModule(this)).build().inject(this);

3 基本使用总结

这里写图片描述

如果能看懂上面的东西。大概就算是入门了吧。嗯嗯,基本操作。

接下来我们就慢慢扩充我们的需求。慢慢融入到我们的真实项目。


循循渐进的项目搭建

先看一段代码:

这里写图片描述

UserModule:很简单就提供一个Gson

@Module
public class UserModule {@ProvidesGson provideGson() {return new Gson();}}

Component

@Component(modules = UserModule.class)
public interface MainComponent {void inject(MainActivity mainActivity);
}

activity:注入2个Gson.

    @InjectGson mGson1;@InjectGson mGson2;@Overrideprotected 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@SingletonGson provideGson() {return new Gson();}

Component

@Singleton
@Component(modules = UserModule.class)
public interface MainComponent {void inject(MainActivity mainActivity);
}

activity 不改。看看结果

这里写图片描述

就是那么简单。

@Singleton

注意事项:

  • 别想的太难,仅仅只标记而已,通过这个标记。dagger2获取实例的方法会生成单例。具体的可以看看生成后的源码

  • module提供对象的方法用@Singleton注解声明,其Component也要保持一致哦。不然会编译不通过。

  • 除了上面要module和Component要使用同一个之外。想要要保证对象的全局单例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;@Overridepublic 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@SingletonApplication providesApplication() {return mApplication;}@Provides@SingletonSharedPreferences providesSharedPreferences(Application application) {return PreferenceManager.getDefaultSharedPreferences(application);}
}

NetModule :公共网络请求,使用的是 retrofit2, 根据自己的情况搭建

@Module
public class NetModule {String mBaseUrl;// 构造module所需要的参数。根据每个人的情况而定public NetModule(String baseUrl) {this.mBaseUrl = baseUrl;}@Provides@SingletonCache provideOkHttpCache(Application application) {int cacheSize = 10 * 1024 * 1024; // 10 MiBreturn new Cache(application.getCacheDir(), cacheSize);}@Provides@SingletonGson provideGson() {GsonBuilder gsonBuilder = new GsonBuilder();gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);return gsonBuilder.create();}@Provides@SingletonHttpLoggingInterceptor provideHttpLoggingInterceptor() {HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);return interceptor;}@Provides@SingletonOkHttpClient 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@SingletonRetrofit 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 {@Overridepublic 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;@Overridepublic void onCreate() {super.onCreate();mAppComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).netModule(new NetModule("www.github.com")).build();}public AppComponent getAppComponent() {return mAppComponent;}}

AMainActivity

 @InjectRetrofit mRetrofit;@Overrideprotected 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() {@Overridepublic void onClick(View v) {startActivity(new Intent(AMainActivity.this,BMainActivity.class));}});}

BMainActivity

 @InjectRetrofit mRetrofit;@Overrideprotected 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


@Component dependencies

很简单,直接看代码。
假设我们AMainActivity 需要Amodule 提供业务对象。各位根据实际情况而定

@Module
public class AModule {@ProvidesUserService 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 需要的对象。各位根据直接的情况而定。//gsonGson 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

 在看别人的项目的时候通常会看到两个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@ActivityScopeUserService 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统筹全局。当然,这不是重点。

重要的是怎么理解这些知识点。正所谓万变不离其宗。

项目的基本搭建就到此结束了。接下来是一些优化和其他相关注解。


项目搭建优化

这里写图片描述

Binding Instances 构建方式

我们可以看到上面搭建的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@SingletonApplication providesApplication() {return mApplication;}*/@Provides@SingletonSharedPreferences 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@SingletonRetrofit 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();}//gsonGson 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);

Reusable Scope 作用域

 在上面我们使用到了Singleton 和 自定义了 activityScopefragmentScope。定义他们的原因可以复用对象,并且可以保证局部单例。

 假如你仅仅是需要缓存依赖的实例,达到复用的效果。且不需要那么多的scope约束。可以考虑用这个替换。

Reusable 作用域不关心绑定的 Component,只需要标记目标类或 provide 方法即可。

 项目作用域优化,重新修改一下module

  • module中Provides下面的Singleton替换为Reusable
  • 删除component上面的Scope

AppModule2

@Module
public class AppModule2 {@Provides@Reusable //替换原来ScopeSharedPreferences 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();}//gsonGson 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;@Overridepublic void onCreate() {super.onCreate();mAppComponent2 = DaggerAppComponent2.builder().application(this).baseUrl("https://api.xxx.com/").build();}public AppComponent2 getAppComponent2() {return mAppComponent2;}

然后 使用测试打印

Di2Activity

 @InjectRetrofit mRetrofit;MyApplication myApplication = (MyApplication) getApplication();DaggerActivityComponent2.builder().appComponent2(myApplication.getAppComponent2()).build().inject(this);Log.w("Di2Activity",mRetrofit.toString());

Di2Activity2

  @InjectRetrofit mRetrofit;MyApplication myApplication = (MyApplication) getApplication();DaggerActivityComponent2.builder().appComponent2(myApplication.getAppComponent2()).build().inject(this);Log.w("Di2Activity2",mRetrofit.toString());

查看结果

这里写图片描述

这样就保证了对象的复用了


扩展库dagger.adnroid

 为什么会出现这个扩展库呢?英文好大的大兄弟可以去看官网的介绍Dagger.android。

不好的话 那只能看我吹牛逼 简单的翻译了。
这里写图片描述
如果fagment 和activity 要用到对象就不得不使用Dagger依赖注入实例。

public class FrombulationActivity extends Activity {@Inject Frombulator frombulator;@Overridepublic 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();@ContributesAndroidInjectorDi2Activity4 di4ActivityInjector();//...省略
}

DiModule 提供一个业务类

@Module
public class DiModule {@Provides@ReusableDouBanService 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<Book>() {@Overridepublic 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.Builderinterface Builder {// Module所需要的参数可以这样提供@BindsInstanceBuilder application(Application application);@BindsInstanceBuilder baseUrl(String baseUrl);AppComponent2 build();}//gsonGson gson();Application application();OkHttpClient okHttpClient();SharedPreferences sharedPreferences();Retrofit retrofit();void inject(MyApplication application);
}

MyApplication2

public class MyApplication2 extends Application implements HasActivityInjector {@InjectDispatchingAndroidInjector<Activity> dispatchingActivityInjector;@Overridepublic void onCreate() {super.onCreate();DaggerAppComponent2.builder().baseUrl("https://api.douban.com/").application(this).build().inject(this);}@Overridepublic AndroidInjector<Activity> activityInjector() {return dispatchingActivityInjector;}
}

最后新建一个BaseActivity

public abstract class BaseActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {//统一注入,要在super之前。AndroidInjection.inject(this);super.onCreate(savedInstanceState);setContentView(layout());init();}protected abstract void init();@LayoutResprotected abstract int layout();
}

然后让Activity继承BaseActivity.直接使用即可

public class Di2Activity3 extends BaseActivity {@InjectRetrofit mRetrofit;@InjectDouBanService mDouBanService;@Overrideprotected void init() {Log.w("Di2Activity2",mRetrofit.toString());findViewById(R.id.tv_text2).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startActivity(new Intent(Di2Activity3.this,Di2Activity4.class));}});mDouBanService.request();}@Overrideprotected int layout() {return R.layout.activity_main;}
}

结果
这里写图片描述

fragment中怎么使用 和 源码就不分析了。可以参考下,下面几位大兄弟的文章

Dagger 2应用于Android的完美扩展库-dagger.android

告别Dagger2模板代码:DaggerAndroid原理解析

顺便可以参考一下googlesamples中,dagger的使用实战。

googlesamples todo-mvp-dagger


其他注解

@Qualifier和@Named

  这两个注解都是同一个意思。就是当你的module提供了同一个对象。然而在使用的时候dagger2不知道用那个。
 限定符为依赖分别打上标记,指定提供某个依赖

@Named

@Module
public class UserModule {@Provides@Singleton@Named("Book1")Book provideBook1() {Book book = new Book();book.setTitle("语文");return book;}@Provides@SingletonBook provideBook2() {Book book = new Book();book.setTitle("数学");return book;}
}

比如我要上面语文的对象
activity

   @Inject@Named("Book1")Book mBook;

在module中比如要语文的对象

 @Provides@SingletonString provideBook(@Named("Book1")Book book) {return book.getTitle();}

@Qualifier
和上面的一个Scope一个鸟样。自定义@Qualifier

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BookQualifier {}

然后module

    @Provides@Singleton@BookQualifierBook provideBook2() {Book book = new Book();book.setTitle("数学");return book;}

使用
activity

 @Inject@BookQualifierBook mBook2;

module

@Provides@SingletonString provideBook(@BookQualifier Book book) {return book.getTitle();}

完成

Lazy (延迟注入)

就是想在使用时再完成初始化,加快速度。
activity

@InjectLazy<Gson> mGson3;//在想要使用的地方
Gson gson = lazyCar.get();

只有在调用 Lazy 的 get() 方法时才会初始化依赖实例注入依赖。

SubComponent

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 继承 AppComponentSubActivityComponentSub 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;@Overridepublic 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

 @InjectUserService mUserService;MyApplication myApplication =  (MyApplication)getApplication();myApplication.getAppComponentSub().activityComponentSub().inject(this);Log.w("AMainActivity", mUserService.toString());

这里写图片描述

可以看下这大兄弟的详情文章。说的很详细

Dagger 2 完全解析(三),Component 的组织关系与 SubComponent

总结

如果能看到这里的都是真爱

这里写图片描述

还是那句话。取其精华,去其糟粕

Dagger2demo

这篇关于Dagger2的入坑指南[捂脸][详]!!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/687076

相关文章

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(五):Blender锥桶建模

前言 本系列教程旨在使用UE5配置一个具备激光雷达+深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客往期教程: 第一期:基于UE5和ROS2的激光雷达+深度RG

如何掌握面向对象编程的四大特性、Lambda 表达式及 I/O 流:全面指南

这里写目录标题 OOP语言的四大特性lambda输入/输出流(I/O流) OOP语言的四大特性 面向对象编程(OOP)是一种编程范式,它通过使用“对象”来组织代码。OOP 的四大特性是封装、继承、多态和抽象。这些特性帮助程序员更好地管理复杂的代码,使程序更易于理解和维护。 类-》实体的抽象类型 实体(属性,行为) -》 ADT(abstract data type) 属性-》成

使用条件变量实现线程同步:C++实战指南

使用条件变量实现线程同步:C++实战指南 在多线程编程中,线程同步是确保程序正确性和稳定性的关键。条件变量(condition variable)是一种强大的同步原语,用于在线程之间进行协调,避免数据竞争和死锁。本文将详细介绍如何在C++中使用条件变量实现线程同步,并提供完整的代码示例和详细的解释。 什么是条件变量? 条件变量是一种同步机制,允许线程在某个条件满足之前进入等待状态,并在条件满

Java 入门指南:Java 并发编程 —— 并发容器 ConcurrentLinkedDeque

文章目录 ConcurrentLinkedDeque特点构造方法常用方法使用示例注意事项 ConcurrentLinkedDeque ConcurrentLinkedDeque 是 Java 并发工具包(java.util.concurrent 包)中的一个线程安全的双端队列(Deque)实现,实现了 Deque 接口。它使用了链表结构,并且针对高并发环境进行了优化,非常适合

使用Nginx部署前端Vue项目的详细指南

在本文中,我们将详细介绍如何使用Nginx部署一个前端Vue项目。此过程涵盖Vue项目的构建、Nginx的安装与配置、以及最后的项目启动。下面是步骤的详细说明。 步骤 1: 准备你的Vue项目 确保你已经创建并构建了一个Vue项目。如果你尚未创建Vue项目,可以使用以下命令创建一个: # 安装Vue CLInpm install -g @vue/cli# 创建一个新的Vue项目vue c

入门指南 | Datavines 安装部署篇

摘要:本文主要介绍基于源码部署 Datavines 和执行检查作业,内容主要分为以下几个部分: 平台介绍快速部署运行数据质量检查作业 Datavines 的目标是成为更好的数据可观测性领域的开源项目,为更多的用户去解决元数据管理和数据质量管理中遇到的问题。在此我们真诚欢迎更多的贡献者参与到社区建设中来,和我们一起成长,携手共建更好的社区。 https://github.com/dat

如何将卷积神经网络(CNN)应用于医学图像分析:从分类到分割和检测的实用指南

引言 在现代医疗领域,医学图像已经成为疾病诊断和治疗规划的重要工具。医学图像的类型繁多,包括但不限于X射线、CT(计算机断层扫描)、MRI(磁共振成像)和超声图像。这些图像提供了对身体内部结构的详细视图,有助于医生在进行准确诊断和制定个性化治疗方案时获取关键的信息。 1. 医学图像分析的挑战 医学图像分析面临诸多挑战,其中包括: 图像数据的复杂性:医学图像通常具有高维度和复杂的结构

从零开始构建大语言模型并进行微调:全面指南

要从0开始搭建并训练一个大语言模型(LLM),涉及到多个步骤和资源,包括理论理解、工具使用、数据准备、模型训练与微调。以下是一个从基础到应用的指南,帮助你理解并逐步实现这一目标。 1. 理解基础概念 在开始搭建大语言模型之前,了解以下基本概念至关重要: 生成式AI:通过大语言模型生成自然语言文本,例如GPT、BERT等。机器学习:通过数据训练模型,使其具备从数据中学习规律的能力。深度学习:机