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的目的?看了许许多多的文章,都指向一个观点,一切是为了解耦。

Dagger2的入坑指南[捂脸][详]!!_第1张图片

从需求的角度

 比如业务类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。直接 上代码说明

Dagger2的入坑指南[捂脸][详]!!_第2张图片

1 业务类。对构造函数进行声明标识,告诉Dagger。生成对象时可以使用这个构造方法。

public class UserService {
  @Inject //(1) 
    UserService() {
    }

    //假设请求网络数据方法
    public void request(){
    }
}

2 还需要一个桥梁Component,和activity产生产生关系。

@Component
public interface MainComponent {
    //说明要在那个activity注入
    void inject(MainActivity mainActivity);
}

3.写好之后进行重构生成注入代码。

Dagger2的入坑指南[捂脸][详]!!_第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();     
        }
}

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

@inject

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

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

@Component

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

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

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

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


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

Dagger2的入坑指南[捂脸][详]!!_第4张图片

业务类的修改,假设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);
    }
*/
}

@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

 @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);

3 基本使用总结

Dagger2的入坑指南[捂脸][详]!!_第5张图片

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

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


循循渐进的项目搭建

先看一段代码:

Dagger2的入坑指南[捂脸][详]!!_第6张图片

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 不改。看看结果

这里写图片描述

就是那么简单。

@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;

 @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


@Component dependencies

很简单,直接看代码。
假设我们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

 在看别人的项目的时候通常会看到两个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

Dagger2的入坑指南[捂脸][详]!!_第7张图片

fragment

Dagger2的入坑指南[捂脸][详]!!_第8张图片

项目dagger2结构

Dagger2的入坑指南[捂脸][详]!!_第9张图片

这样做也行,但是会写比较多的 Component和module。

我就是懒一点。直接2个Component统筹全局。当然,这不是重点。

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

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


项目搭建优化

Dagger2的入坑指南[捂脸][详]!!_第10张图片

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
    @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);

Reusable Scope 作用域

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

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

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

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

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

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.adnroid

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

不好的话 那只能看我吹牛逼 简单的翻译了。
Dagger2的入坑指南[捂脸][详]!!_第11张图片
如果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


其他注解

@Qualifier和@Named

  这两个注解都是同一个意思。就是当你的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();
    }

完成

Lazy (延迟注入)

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

@Inject
 Lazy 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 继承 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

总结

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

Dagger2的入坑指南[捂脸][详]!!_第12张图片

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

Dagger2demo

你可能感兴趣的:(dagger2)