这几天真心为了学习dagger2花费了很多精力,对于什么@Scope、@Provides、@Component、@Module、@Named之类的关键字还比较好理解,其实关于编译后的dagger源码也都比较好理解,也正是因为读dagger2编译源码知道dagger2不是基于反射来实现的依赖注入,而是通过apt包生成对应工厂类来实现依赖注入。既然这些都知道了按理说使用dagger2应该不是什么难题了,的确,一般的使用是没什么问题了,但是无意中看见dagger2的组件依赖以及子组件的文章,文章写得很好,就是不是很好理解,就是那种懂得能看懂,不懂得很难懂得那种类型,于是决定自己在这里总结一下。而这篇文章,就是主要围绕“多Module组件使用”、”组件依赖”、“子组件”这三部分的使用和区分来进行讲解。

1、多Module的组件使用

我们知道Component的作用是连接Module和@Inject的(其实也可以单纯的连接两个@Inject,个人觉得连接@Module和@Inject的用法更加常规),那么存在一个Module对应一个Component的情况,也就存在多个Module对应一个Component的情况,那么废话不多说,直接贴代码。

AppModule.class

@Module
public class AppModule {
    private MyApplication myApplication;
    public AppModule(MyApplication myApplication){
        this.myApplication = myApplication;
    }

    @Singleton
    @Provides
    public Context providesContext(){
        return myApplication;
    }
}

MultiTestModule

@Module
public class MultiTestModule {
    public MultiTestModule(){

    }

    @Singleton
    @Provides
    public String providesStr(Context context){
        return  "string from myapplication" + context.getCacheDir().getPath();
    }
}

MultiTestComponent.class

@Singleton
@Component(modules = {AppModule.class, MultiTestModule.class})
public interface MultiTestComponent {
    void inject(DaggerActivity activity);
}

DaggerActivity.class

@Inject String mutliStr;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        DaggerMultiTestComponent.builder()
                .appModule(new AppModule((MyApplication)this.getApplication()))
                .multiTestModule(new MultiTestModule())
                .build()
                .inject(this);
        Log.i("yoryky", "string from multistr: " + mutliStr );
    }

以上代码是指贴出了核心代码,当然就依照这些代码,已经可以在本地自己做测试了,不过文章最后还是会贴出来源码地址的。

有一点需要注意是,这里的AppModule和MultiTestModule两个Module共同对应一个Component,同事要注意这两个Module的声明周期的都是相同的@Singleton,这一点区别于后面要讲的组件依赖和子组件。至于多Module的使用场景是很多的,一个典型就是你想有自己的Application对应的AppModule同时,有需要一个NetServer进行网络访问,但是这个使用NetServer的对象中,又可能需要AppModule中实现的依赖注入,那么就可以在NetServer对应的的

2、组件依赖的使用

组件依赖同多Module对应一个Component的情况一样,也是存在多个Module情况,不过组件依赖的多Module对应多个Component,也直接先上代码吧。

AppModule.class

@Module
public class AppModule {
    private MyApplication myApplication;
    public AppModule(MyApplication myApplication){
        this.myApplication = myApplication;
    }

    @Singleton
    @Provides
    public Context providesContext(){
        return myApplication;
    }
}

AppComponent.class

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
    Context context();
}

DependTestModule.class

@Module
public class DependTestModule {
    public DependTestModule(){

    }

    @DependScope
    @Provides
    public DaggerUtil providesDaggerUtil(Context context){
        return new DaggerUtil(context);
    }
}

DependTestComponent.class

@DependScope
@Component(dependencies = {AppComponent.class},modules = {DependTestModule.class})
public interface DependTestComponent {
    void inject(DaggerActivity activity); 
}

DaggerActivity.class

@Inject DaggerUtil daggerUtil;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    DaggerDependTestComponent.builder()
           .appComponent(((MyApplication)getApplication()).getAppComponent())
           .dependTestModule(new DependTestModule())
           .build()
           .inject(this);
    daggerUtil.test();

}

以上代码可以看出,DependTestComponent依赖AppComponent,这种依赖的实现在代码上表现为
在DependTestComponent中标明依赖关系

dependencies = {AppComponent.class}

然后在AppComponent中暴露出来提供给DependTestComponent的依赖

Context context();

其中这里的context()方法名随意写,如果AppModule中对应实现方法有参数也不用写参数,关键是写好返回参数Context就行,这样DependTestModule的providesDaggerUtil方法中的Context就通过AppModule依赖注入,就不用手动传参数了。

同事还应该注意的就是,AppModule和DependTestModule的Scope不一样,这里贴出来DependScope的代码吧。

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

3、子组件的使用

其实子组件和依赖组件的作用,个人感觉大同小异,都是方便使用其它Module中的实现,以便完成自己Module中的依赖注入,这句话可能也是懂得懂,不懂得不懂,还是看代码吧。

ChildModule.class

@Module
public class ChildModule {
    public ChildModule(){

    }

    @ChildScope
    @Provides
    public DaggerUtil providesDaggerUtil(Context context){
        return new DaggerUtil(context);
    }
}

ChildComponent.class

@ChildScope
@Subcomponent(modules = {ChildModule.class})
public interface ChildComponent {
    void inject(DaggerActivity activity);
}

ParentModule.class

@Module
public class ParentModule {
    private Context context;
    public ParentModule(Context context){
        this.context = context;
    }

    @ParentScope
    @Provides
    public Context providesContext(){
        return this.context;
    }

    @ParentScope
    @Provides
    public User providesUser(){
        Child child = new Child();
        return new User(child);
    }

}

ParentComponent.class

@ParentScope
@Component(modules = {ParentModule.class})
public interface ParentComponent {
    ChildComponent newChildComponent(ChildModule childModule);
}

DaggerActivity.class

@Inject User user;
@Inject DaggerUtil daggerUtil2;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); 
    /** 测试子组件*/
    ParentComponent parentComponent = DaggerParentComponent.builder()
            .parentModule(new ParentModule(this))
            .build();
    parentComponent.newChildComponent(new ChildModule()).inject(this);
    user.test();
    daggerUtil2.test();
}

从代码可以看出子组件和组件依赖一样,父子组件的Scope不能一样(定义同DependScope,改个名字而已),但是不一样的点在与子组件可以使用父组件所有的Module实现进行依赖注入,同时在构建子组件时的代码实现方式也和构建组件依赖时不一样。

实现子组件很简答,ParentComponent中显示声明子组件

ChildComponent newChildComponent(ChildModule childModule);

其中方法名随意些,只是传参和返回参数要求对应写。

自组件ChildComponent中通过Subcomponent来完成子组件身份的说明

@Subcomponent(modules = {ChildModule.class})

使用子组件时,其实是通过父组件newChildComponent来完成注入的(就是我们在父组件中定义的那个方法),这一点看代码。

于是乎,子组件的说明也就结束了。

4、源码地址

本文关于组件实现方式及使用其实算是写的很详细了,但是还是把源码地址贴出来吧,反正就是自己平时的学习demo。

https://github.com/Yoryky/AndroidDemo.git

5、参考文献

这里的参考文献,不一定是对本文有帮助的,但是一定都是与dagger2相关的,因为dagger2学习曲线稍微陡峭一点,这些文章这几天算是帮了我大忙,这里贴出来就算是帮着推广下吧。

1、Dagger2从入门到放弃再到恍然大悟:
http://www.jianshu.com/p/39d1df6c877d

3、更清晰的Dagger2 + MVP 架构:
http://www.jianshu.com/p/a1613d94ddbe

4、dagger2:组件依赖和子组件的区别
http://www.jianshu.com/p/5ce4dcc41ec7