dagger2 循序渐进学习(包会)(三) 实例1,application中的应用

文章索引
dagger2 循序渐进学习(一)依赖注入基础知识(包会)
dagger2 循序渐进学习(二)
dagger2 循序渐进学习(三) 实例1,application中的应用

前两篇dagger2的文章介绍了其基本的使用方法,但其使用中还有很多重要的细节需要我们掌握,我认为在实例中学习比罗列一大堆的理论名称解释要来的实在。所以接下来每篇文章主要以一个马上能应用起来的小实例去解释一个个知识点,文章在精不在多,希望我写的文字能达到这样的效果吧!

dagger2 知识点

一、@Inject

先来说下上一篇文章dagger2 循序渐进学习(二) ,文中的activity

public class LoginActivity extends AppCompatActivity  implements ILoginContract.ILoginView{
@Inject//这里加注解
LoginPresenter presenter;


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

@Override
public void loginok() {

}

@Override
public void loginErro() {

}
}

文中的presenter:

public class LoginPresenter implements     ILoginContract.ILoginPresenter {
ILoginContract.ILoginView view;

@Inject//这里注解
public LoginPresenter(ILoginContract.ILoginView view) {
this.view = view;
}

@Override
public void login(String name, String pwd) {
}
}

有没有发现

Paste_Image.png

presenter注入的类并没有遵循依赖倒置的原则,就是说没有依赖presenter的接口类,如果我们改成其接口类之后运行就会报错

Paste_Image.png

那这是为什么呢,可以看出原因就在@Inject
依赖注入中第一个并且是最重要的就是 @Inject 注解。JSR-330标准中的一部分,标记那些应该被依赖注入框架提供的依赖。在Dagger 2中有3种不同的方式来提供依赖:

构造器注入,

@Inject标注在构造器上其实有两层意思。

①告诉Dagger2可以使用这个构造器构建对象。如 LoginPresenter 类构造方法上的@Inject

②注入构造器所需要的参数的依赖。 如 Pot 类,构造上的Rose会被注入。又如 LoginPresenter 类构造方法上的@Inject实现①的功能外,它本身还需要ILoginContract.ILoginView的依赖,此时的注入实际就在dagger2框架中 LoginModule中提供的,只是什么时候怎么提供的我们暂时不得而知

Paste_Image.png

构造器注入的局限:如果有多个构造器,我们只能标注其中一个,无法标注多个。

属性注入

如 LoginActivity 类,标注在属性上。被标注的属性不能使用 private 修饰,否则无法注入。

属性注入也是Dagger2中使用最多的一个注入方式。
看到这里应该明白了LoginPresenter是如何注入到LoginActivity中的了:就是1在LoginActivity属性上标注@Inject ,2在LoginPresenter的构造方法上同时标注@Inject,编译过程中,dagger2就知道了LoginActivity的presenter属性需要注入,接下来就去寻找哪里可以提供,其中一项就是就是找有没有相应类的构造器用@Inject标注的,如果有就用这个构造器构造后注入activity。所以当我们把LoginActivity中的属性改成ILoginPresenter接口类型的时候,dagger2就找不到了他的构造器了,所以就报错了。

方法注入

Paste_Image.png

标注在public方法上,Dagger2会在构造器执行之后立即调用这个方法。

方法注入和属性注入基本上没有区别, 那么什么时候应该使用方法注入呢?

比如该依赖需要this对象的时候,使用方法注入可以提供安全的this对象,因为方法注入是在构造器之后执行的

比如google mvp dagger2中,给View设置Presenter的时候可以这样使用方法注入。

/**
 * Method injection is used here to safely reference {@code    this} after the object is created.
 * For more information, see Java Concurrency in Practice.
 */
@Inject
void setupListeners() {
 mTasksView.setPresenter(this);
 }

二、@Component

@Inject 注解是JSR-330中定义的注解,在 javax.inject 包中。
这个注解本身并没有作用,它需要依赖于注入框架才具有意义,用来标记需要被注入框架注入的方法,属性,构造。
而Dagger2则是用 Component 来完成依赖注入的, @Component 可以说是Dagger2中最重要的一个注解。
@Componentpublic interface MainActivityComponent { void inject(MainActivity activity);}

以上是定义一个Component的方式。使用接口定义,并且 @Component 注解。
命名方式推荐为: 目标类名+Component ,在编译后Dagger2就会为我们生成 DaggerXXXComponent 这个类,它是我们定义的 xxxComponent 的实现,在目标类中使用它就可以实现依赖注入了。
Component中一般使用两种方式定义方法。
void inject(目标类 obj); Dagger2会从目标类开始查找@Inject注解,自动生成依赖注入的代码,调用inject可完成依赖的注入。
Object getObj(); 如: LoginPresenter getLoginPresentert();Dagger2会到LoginPresenter类中找被@Inject注解标注的构造器,自动生成提供LoginPresenter依赖的代码,这种方式一般为其他Component提供依赖。(一个Component可以依赖另一个Component,后面会说)

Component和Inject的关系如下:


Dagger2框架以Component中定义的方法作为入口,到目标类中寻找JSR-330定义的@Inject标注,生成一系列提供依赖的Factory类和注入依赖的Injector类。
而Component则是联系Factory和Injector,最终完成依赖的注入。

三、@Module和@Provides

使用@Inject标记构造器提供依赖是有局限性的,比如说我们需要注入的对象是第三方库提供的,我们无法在第三方库的构造器上加上@Inject注解。
或者,我们使用依赖倒置的时候,因为需要注入的对象是抽象的,@Inject也无法使用,因为抽象的类并不能实例化比如咱们需要ILoginPresenter的接口类的依赖,会出现文中最开始的那个错误;

这个时候就需要Module了。
先清除LoginPresenter中的@Inject

Paste_Image.png

并把LoginAcitivity中的依赖改成接口类型

Paste_Image.png

@Module标记在LoginModule类上面,@Provodes标记在方法上,表示可以通过这个方法获取依赖。

Paste_Image.png

在@Component中指定Module


Paste_Image.png

这样就完了,ok了。测测,没有问题;
@Module和@Provides的作用:
@Module需要和@Provide是需要一起使用的时候才具有作用的,并且@Component也需要指定了该Module的时候。

@Module是告诉Component,可以从这里获取依赖对象。Component就会去找被@Provide标注的方法,相当于构造器的@Inject,可以提供依赖。

还有一点要说的是,@Component可以指定多个@Module的,如果需要提供多个依赖的话。

并且Component也可以依赖其它Component存在。
如此便解决上面提到的问题;回顾一下这四个最重要的注解的用法。接下来我们研究个小实例。

实例

这个实例就是我们经常要实现的application中retrofit的应用。为了节省资源提高性能,要求我们在使用retrofit时候,整个app中retrofit是单例的,然后再用他create相应的api的接口类实例以往我们经常会写一大堆代码和模式来实现其单例,在dagger中这一切变得简单。下面开始撸代码:
相关的第三方库的依赖就不写了;
api的请求接口是这样婶儿滴

public interface ApiService {
@GET("/users/{user}/repos")
Observable<ArrayList<String>> getRepoData(@Path("user") String user);
}

再上个module

@Module
public class ServiceModule {

@Provides
public OkHttpClient provideOkHttpClient() {
    OkHttpClient okHttpClient ;
    OkHttpClient.Builder builder= new OkHttpClient.Builder();
    okHttpClient=builder.readTimeout(60 * 1000, TimeUnit.MILLISECONDS)
            .connectTimeout(60 * 1000, TimeUnit.MILLISECONDS)
            .build();
    return okHttpClient;
}

@Provides
public Retrofit provideRetrofit(Application application, OkHttpClient okHttpClient){
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(application.getString(R.string.api_host))
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 添加Rx适配器
            .addConverterFactory(GsonConverterFactory.create()) // 添加Gson转换器
            .client(okHttpClient)
            .build();
    return retrofit;
}
@Singleton
@Provides
protected ApiService provideGitHubService(Retrofit retrofit) {

    return retrofit.create(ApiService.class);
}

}

再来个module

@Module
public class AppModule {
private final Application application;

public AppModule(Application application) {
    this.application = application;
}

@Provides
public Application provideApplication() {
    return application;
}

}

那么再来看我们的application类中

public class App extends Application {
private  AppComponent appComponent;
@Override
public void onCreate() {
    super.onCreate();
   appComponent=
           DaggerAppComponent.builder()
           .appModule(new AppModule(this))
           .serviceModule(new ServiceModule())
           .build();
}

public  AppComponent getAppComponent() {
    return appComponent;
}
}

眼尖的同学看到了@Singleton,这个先不说,其他的不用我多说,相信前面都看懂了的同学,这几个类完全能看懂。

@Singleton顾名思义,就是单例啊,但是这个单例可不是怎么用都是单例。通过测试,我们发现当重新build一个Component的时候,这个单例也是新的,所以准确的说 ,它的作用只是保证依赖在@Component中是唯一的,可以理解为“局部单例”。所以在application中实例化Component,其他地方用到它的时候就需要先在application获取appComponent进行注操作。
通过这个方法,当然如果也可以把他定义为static方法

public  AppComponent getAppComponent() {
return appComponent;
}

接下来我们遵循循序渐进的原则dagger2还有部分知识点会在后面的文章继续和大家分享,相信通过循序渐进的边学边实践的方式,学习起来更扎实,不像一口吞个胖子样!!

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

推荐阅读更多精彩内容