dagger2学习笔记1

添加依赖

//    dagger
implementation 'com.google.dagger:dagger:2.15'
annotationProcessor 'com.google.dagger:dagger-compiler:2.15'

添加代码

添加一个presenter

public class ScanPresenter {

  public static final String TAG = "ScanPresenter";

  @Inject
  public ScanPresenter(Activity activity) {
    mActivity = activity;
  }

}

记得在构造方法上添加@Inject注解

在activity中使用这个presenter

public class MainActivity extends AppCompatActivity {

  private static final String TAG = "MainActivity";
  
// 添加inject注解,不用通过new来手动实例化
  @Inject
  ScanPresenter mScanPresenter;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
  }

添加ActivityModule用来对外提供activity实例。因为presenter的构造函数需要用到。

@Module
public class MainActivityModule {
  private Activity mActivity;

  public MainActivityModule(Activity activity) {
    mActivity = activity;
  }

  @Provides
  public Activity getActivity() {
    return mActivity;
  }
}

添加对应的Component用于执行注入操作。也就是注入的入口

@Component(modules = {MainActivityModule.class})
public interface MainActivityComponent {
  void inject(MainActivity activity);

ScanPresenter getPresenter();
}

在对应activity中添加注入代码

public class MainActivity extends AppCompatActivity {
  private static final String TAG = "MainActivity";
  
  @Inject
  ScanPresenter mScanPresenter;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
      .mainActivityModule(new MainActivityModule(this))
      .build();
    mainActivityComponent.inject(this);
  }
}

小结:

  • 提供实例的注解有@Inject@Module@Provides。其中@Inject用于构造函数,@Module@Provides用于无法在对应构造函数上添加Inject注解的实例(比如第三方包,android系统类等等)。
  • 注入实例的注解@Inject
  • 注解的入口@Component,里面需要添加对应的modules或者依赖,这个是执行依赖注入的入口,也就是说对应的类的实例会在这里实例化。也可以在这个接口里通过添加对应返回值的函数来获取这个类型的实例(比如MainActivityComponent中的getPresenter方法)。

多component之间相互依赖

添加retrofit的依赖用来发送网络请求

@Module
public class NetModule {

  public String BASE_RUL = "";

  @Singleton
  @Provides
  public Retrofit provideRetrofit(OkHttpClient okHttpClient) {
    return new Retrofit.Builder()
      .client(okHttpClient)
      .baseUrl(BASE_RUL)
      .addConverterFactory(FastJsonConverterFactory.create())
      .build();
  }

  @Singleton
  @Provides
  public OkHttpClient provideHttpClient() {
    return new OkHttpClient.Builder()
      .build();
  }

}

添加网络接口

public interface TransactionService {

  @FormUrlEncoded
  @POST("/broadcast-tx")
  Call<SendResult> send(@Field("coin_type") String coinType, @Field("signed_tx") String signedData, @Field("origin_data") String originData);

}

提供接口的module

@Module
public class ServiceModule {
  @Provides
  public TransactionService provideTransaction(Retrofit retrofit) {
    return retrofit.create(TransactionService.class);
  }
}

添加AppModule用来提供applicationContext,但是现在暂时没用到。

@Module
public class AppModule {
  private MyApplication mMyApplication;

  public AppModule(MyApplication myApplication) {
    mMyApplication = myApplication;
  }

  @Singleton
  @Provides
  public MyApplication provideApplication() {
    return mMyApplication;
  }

}

添加AppComponent

@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {

  MyApplication application();

  Retrofit getRetrofit();

}

在application中实例化这些代码。(先编译一下,生成一些类)

public class MyApplication extends Application {

  private AppComponent mAppComponent;
  private static MyApplication sContext;

  @Override
  public void onCreate() {
    super.onCreate();
    sContext = this;
    mAppComponent = DaggerAppComponent.builder()
      .appModule(new AppModule(this))
      .build();
  }

  public static MyApplication getContext() {
    return sContext;
  }

  public AppComponent getAppComponent() {
    return mAppComponent;
  }
}

主要是实例化AppModule这个类。提供application的实例。

添加一个scope

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}

添加MainActivityModule

@Module
public class MainActivityModule {
  private MainActivity mActivity;

  public MainActivityModule(MainActivity activity) {
    mActivity = activity;
  }

  @ActivityScope
  @Provides
  public MainActivity getActivity() {
    return mActivity;
  }
}

添加MainActivityComponent

@ActivityScope
@Component(modules = {MainActivityModule.class, ServiceModule.class}, dependencies = {AppComponent.class})
public interface MainActivityComponent {

  void inject(MainActivity activity);

}

这里就是一个component依赖另一个component,通过dependencies来表示依赖关系。因为我们的retrofit是需要AppComponent提供的,所以需要添加这个,还有一个需要注意的点是:MainActivityComponent需要的依赖,在AppComponent中需要要提供一个具体的方法,比如这里AppComponent中的Retrofit getRetrofit();方法,因为这个Retrofit是MainActivityComponent需要的依赖,不然会报错。

在mainActivity中添加注入的入口

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    AppComponent appComponent = MyApplication.getContext().getAppComponent();
    MainActivityComponent component = DaggerMainActivityComponent.builder()
      .appComponent(appComponent)
      .mainActivityModule(new MainActivityModule(this))
      .build();
    component.inject(this);

  }

小结

这里有两个点

  • 多component依赖的时候,被依赖的component要显示的提供依赖方法,而不是有provides标注或者Inject标注提供了就好了比如这里AppComponent中提供的getRetrofit方法。
  • 使用dependencies的时候,对于像activity等等有自己的生命周期的,需要用@scope(也就是这里的ActivityScope)限定一下。不然会有报错提示。

生成的代码分析

public final class DaggerMainActivityComponent implements MainActivityComponent {
  private ServiceModule serviceModule;

  private AppComponent appComponent;

  private Provider<MainActivity> getActivityProvider;

看DaggerMainActivityComponent里有三个变量,这三个变量就是在声明DaggerMainActivityComponent在注解里写的,两个是modules, 一个是dependencies,看这三个是如何实例化的?

看builder方法

  public static final class Builder {
    private MainActivityModule mainActivityModule;

    private ServiceModule serviceModule;

    private AppComponent appComponent;

    private Builder() {}

    public MainActivityComponent build() {
      if (mainActivityModule == null) {
        throw new IllegalStateException(
            MainActivityModule.class.getCanonicalName() + " must be set");
      }
      if (serviceModule == null) {
        this.serviceModule = new ServiceModule();
      }
      if (appComponent == null) {
        throw new IllegalStateException(AppComponent.class.getCanonicalName() + " must be set");
      }
      return new DaggerMainActivityComponent(this);
    }

    public Builder mainActivityModule(MainActivityModule mainActivityModule) {
      this.mainActivityModule = Preconditions.checkNotNull(mainActivityModule);
      return this;
    }

    public Builder serviceModule(ServiceModule serviceModule) {
      this.serviceModule = Preconditions.checkNotNull(serviceModule);
      return this;
    }

    public Builder appComponent(AppComponent appComponent) {
      this.appComponent = Preconditions.checkNotNull(appComponent);
      return this;
    }
  }

builder里面可以通过方法设置这些实例,但是有些我们没有设置比如ServiceModule,在build方法里,他会检查,如果他可以帮忙实例化的,就实例化(这里直接new出来了ServiceModule),否则会抛出异常进行提示。

有了对应的辅助类的实例,再看是如何注入的,看入口inject函数:

  @Override
  public void inject(MainActivity activity) {
    injectMainActivity(activity);
  }


  private MainActivity injectMainActivity(MainActivity instance) {
    MainActivity_MembersInjector.injectMScanPresenter(instance, getScanPresenter());
    MainActivity_MembersInjector.injectModel(instance, getTransactionModel());
    return instance;
  }

看这两个方法:

  public static void injectMScanPresenter(MainActivity instance, ScanPresenter mScanPresenter) {
    instance.mScanPresenter = mScanPresenter;
  }

  public static void injectModel(MainActivity instance, TransactionModel model) {
    instance.model = model;
  }

其实就是给对应的变量赋值,这也是为啥@Inject修饰的变量不能是private的。

在看一个方法:

  private TransactionService getTransactionService() {
    return ServiceModule_ProvideTransactionFactory.proxyProvideTransaction(
        serviceModule,
        Preconditions.checkNotNull(
            appComponent.getRetrofit(),
            "Cannot return null from a non-@Nullable component method"));
  }

在获取retrofit的时候,是通过AppComponent获取的,这也是为啥被依赖的component需要显示的提供方法,而不是打标注就好了。

他是在什么时机实例化对象的?
由代码可以看到在build的时候会实例化一些辅助类,比如module等等,而在调用inject方法的时候才会去获取并且实例化这些对象。比如获取presenter。

总结:

  • @Inject标注在构造方法可以提供注解,标注在变量上表示这个变量需要注入。
  • @Module和@provides用于给那些无法打标注的比如第三方包,以及系统去实例化的比如activity等等提供依赖注入。
  • @component管理一个依赖集合,也是依赖的入口,可以多个component相互依赖,但是需要显示的提供被依赖的方法。
  • 当对应依赖已经提供(通过@inject或者provides)的时候,这个类型可以直接作为参数使用,比如provideRetrofit方法将OkHttpClient作为参数,因为OkHttpClient已经可以提供了。

参考文章:
https://juejin.im/post/58722866128fe1006b33e104
https://www.jianshu.com/p/92f793e76654
https://google.github.io/dagger/android

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容

  • dagger2的缘由背景 dagger2除了也有一段时间了,但是现在各大开源项目都在使用它,虽然感觉他的用处并不是...
    vison123阅读 425评论 0 1
  • 系列文章:Dagger2学习笔记(一)Dagger2学习笔记(二) 依赖注入是一种十分好的技巧,它能解偶高层次模块...
    嘉伟咯阅读 521评论 0 3
  • 系列文章:Dagger2学习笔记(一)Dagger2学习笔记(二) 在上一篇文章我们讲了用于搜索的SearchAc...
    嘉伟咯阅读 384评论 0 1
  • Dagger2学习要点理解: Qualifier(限定符,就是解决依赖注入迷失问题的,即对获取对象的筛选或限定);...
    3Q竹林阅读 420评论 0 0
  • There are n bulbs that are initially off. You first tur...
    Shiyi001阅读 204评论 0 0