Dagger2学习笔记(二)

系列文章:
Dagger2学习笔记(一)
Dagger2学习笔记(二)

在上一篇文章我们讲了用于搜索的SearchActivity的实现,这一篇文章我们继续以剩下的两个Activity的实现为例,讲一下Dagger2的其他特性。这两个Activity分别是用了展示SearchActivity搜索的用户的头像和用户名的UserInfoActivity和点击用户头像跳转到的展示用户followers的FollowerActivity。

在我们的Demo中有个叫做UserInfoLoader的类,它是用来向github服务器请求用户信息和follower信息的,会在多个actiity中被使用,例如在FollowerPresenter和UserInfoPresenter中都需要注入UserInfoLoader。最简单的方式是我们可以直接使用@Inject注解标注它的构造方法,使得Dagger2可以直接创建它的实例去注入FollowerPresenter和UserInfoPresenter中。

class UserInfoLoader {
    ...
    @Inject
    UserInfoLoader() {
    }
    ...
}

Module复用

当然我们也能用复用Module的方式,这种方式虽然比直接用@Inject注解构造方法复杂,但是它还有其他十分有用的功能,接下来我会慢慢分析。

首先我们把它的Module单独抽出来,放到AppModule中:

@Module
public class AppModule {
    @Provides
    UserInfoLoader provideUserInfoLoader() {
        return new UserInfoLoader();
    }
}

共用Module

我们复用这个Module的方式有几种,一是同时放在FollowerComponent和UserInfoComponent的modules中:

@Component(modules = {AppModule.class, FollowerPresenterModule.class})
public interface FollowerComponent {
    void inject(FollowerPresenter presenter);
    void inject(FollowerActivity activity);
}

@Component(modules = {AppModule.class, UserInfoPresenterModule.class})
public interface UserInfoComponent {
    void inject(UserInfoPresenter presenter);
    void inject(UserInfoActivity activity);
}

使用dependencies

第二种方式是使用dependencies,首先我们需要声明多一个AppComponent接口

@Component(modules = {AppModule.class})
public interface AppComponent {
    UserInfoLoader provideUserInfoLoader();
}

这个接口的provideUserInfoLoader()方法就是提供出来给子依赖获取UserInfoLoader的,因为dependencies子依赖是获取不了父依赖的modules里面的Provides的。

之后声明FollowerComponent和UserInfoComponent:

@Component(dependencies = AppComponent.class, modules = {UserInfoPresenterModule.class})
public interface UserInfoComponent {
    void inject(UserInfoPresenter presenter);
    void inject(UserInfoActivity activity);
}
@Component(dependencies = AppComponent.class, modules = {FollowerPresenterModule.class})
public interface FollowerComponent {
    void inject(FollowerPresenter presenter);
    void inject(FollowerActivity activity);
}

最后就再去实现注入:

FollowerComponent component = DaggerFollowerComponent.builder()
    .appComponent(getAppComponent())
    .followerPresenterModule(new FollowerPresenterModule(this))
    .build();
component.inject(this);
component.inject(mPresenter);
UserInfoComponent component = DaggerUserInfoComponent.builder()
    .appComponent(getAppComponent())
    .userInfoPresenterModule(new UserInfoPresenterModule(this))
    .build();
component.inject(this);
component.inject(mPresenter);

这里的AppComponent是公用的,所以我们放到Application中:

public class AppApplication extends Application {
    private AppComponent mAppComponent;

    public AppApplication() {
        super();

        mAppComponent = DaggerAppComponent.create();
    }

    public AppComponent getAppComponent() {
        return mAppComponent;
    }
}

然后在Activity中这样获取AppComponent:

AppComponent getAppComponent() {
    return ((AppApplication)getApplication()).getAppComponent();
}

我们尝试注释掉AppComponent.provideUserInfoLoader,rebuild一下,发现居然没有报错,这是怎么回事?其实是因为UserInfoLoader的构造方法使用@Inject注解标注了,所以可以直接通过构造方法创建UserInfoLoader来注入FollowerPresenter和FollowerActivity。

我们再把UserInfoLoader的构造方法的@Inject注解注释掉,这时候再rebuild就可以发现报错了。

然后再取消掉AppComponent.provideUserInfoLoader的注释,就能顺利编过了。因为我们的AppModule.provideUserInfoLoader是通过new 一个UserInfoLoader出来的,所以可以不依赖构造方法的@Inject注解。

使用Subcomponent

最后一种方法就是使用@Subcomponent注解,这中方法和使用dependencies有点像,他们的区别在于使用@Subcomponent方法AppComponent不需要提供一个provideUserInfoLoader方法,子依赖可以直接使用AppComponent中的modules。首先我们要这样声明AppComponent:

@Component(modules = {AppModule.class})
public interface AppComponent {
    FollowerComponent plus(FollowerPresenterModule module);
    UserInfoComponent plus(UserInfoPresenterModule module);
}

然后FollowerComponent和UserInfoComponent的定义如下:

@Subcomponent(modules = {FollowerPresenterModule.class})
public interface FollowerComponent {
    void inject(FollowerPresenter presenter);
    void inject(FollowerActivity activity);
}
@Subcomponent(modules = {UserInfoPresenterModule.class})
public interface UserInfoComponent {
    void inject(UserInfoPresenter presenter);
    void inject(UserInfoActivity activity);
}

注入的实现代码如下:

FollowerComponent component = getAppComponent().plus(new FollowerPresenterModule(this));

component.inject(this);
component.inject(mPresenter);

Scope

现在还有一个问题,现在FollowerComponent和UserInfoComponent虽然都往Presenter注入了UserInfoLoader,但他们是不同的实例:

D/UserInfoPresenter: mUserInfoLoader : com.example.linjw.dagger2demo.model.UserInfoLoader@31e117c
D/FollowerPresenter: mUserInfoLoader : com.example.linjw.dagger2demo.model.UserInfoLoader@c9ad63b

如果我想他们使用的就是同一个UserInfoLoader实例呢?需要怎么做?

Dagger2中有作用域的概念,可以规定几个Component在同一个作用域,在同一个作用域注入的依赖就是同一个实例。

首先需要声明我们的Scope:

@Scope
@Retention(RUNTIME)
public @interface AppScope {
}

然后就只需要将Module的Provides方法和Component用同一个Scope注解标注一下,就能让他们处于同一个作用域了。

比如我们需要在AppModule.provideUserInfoLoader标注:

@Module
public class AppModule {
    @AppScope
    @Provides
    UserInfoLoader provideUserInfoLoader() {
        return new UserInfoLoader();
    }
}

像我们使用Subcomponent去实现依赖继承,我们就只需要在AppComponent中标注就好了,这样他们的子依赖也会处于AppScope中:

@AppScope
@Component(modules = {AppModule.class})
public interface AppComponent {
    FollowerComponent plus(FollowerPresenterModule module);
    UserInfoComponent plus(UserInfoPresenterModule module);
}

D/UserInfoPresenter: mUserInfoLoader : com.example.linjw.dagger2demo.model.UserInfoLoader@31e117c
D/FollowerPresenter: mUserInfoLoader : com.example.linjw.dagger2demo.model.UserInfoLoader@31e117c

Demo地址

可以在这里查看完整代码

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

推荐阅读更多精彩内容