依赖注入框架 -- Dagger2 实践

在基础和进阶两篇文章中,讨论很多的理论知识,不知道你们怎么样,反正我是有点懵逼了,程序猿么,终归是要垒代码。来吧,我们用代码说话,看一看Dagger2到底是怎么个用法。

本文代码地址 Dagger2 示例 app-mvp-dagger2
示例中采用了MVP架构,使用Retrofit进行网络通信,并融入了 Rxjava RxBus 等。Dagger2 使用示例 在 app-mvp-dagger2 分支,请自行chekcout。

依赖标注

@Inject 标注

  • @Inject 注解 BaseActivity 和 BaseFragment 的 Presenter 实例。
1
2
3
4
5
public abstract class BaseActivity<T extends BasePresenter> extends SupportActivity implements BaseView {
@Inject
protected T mPresenter
...
}
1
2
3
4
5
public abstract class BaseFragment<T extends BasePresenter> extends SupportFragment implements BaseView {
@Inject
public T mPresenter;
...
}
  • @Inject标注依赖构造函数
1
2
3
4
5
@Inject
public MainPresenter(RetrofitHelper retrofitHelper) {
this.retrofitHelper = retrofitHelper;
registerEvent();
}
1
2
3
4
 @Inject
public RepositoryPresenter(RetrofitHelper retrofitHelper){
this.retrofitHelper = retrofitHelper;
}

@Moudle 工厂类

  • AppModule 提供全局依赖实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Module
    public class AppModule {
    private final ArchiApplication application;

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

    @Provides
    @Singleton
    ArchiApplication provideApplicationContext(){
    return application;
    }

    @Provides
    @Singleton
    RetrofitHelper provideRetrofitHelper(RepositoriesService repositoriesService, UserInfoService userInfoService){
    return new RetrofitHelper(repositoriesService, userInfoService);
    }

    }
  • ActivityModule 为 Activity 提供 this 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Module
    public class ActivityModule {
    private Activity mActivity;
    public ActivityModule(Activity activity) {
    this.mActivity = activity;
    }
    @Provides
    @ActivityScope
    public Activity provideActivity() {
    return mActivity;
    }
    }
  • FragmentModule 为 Fragment 提供 Activity 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Module
    public class FragmentModule {
    private Fragment fragment;
    public FragmentModule(Fragment fragment) {
    this.fragment = fragment;
    }
    @Provides
    @FragmentScope
    public Activity provideActivity() {
    return fragment.getActivity();
    }
    }

Component组织

Component 是依赖和被依赖的的桥梁,注入依赖。

AppComponent

  • 定义 AppComponent 接口 ,@Singleton 标注,增加可读性
1
2
3
4
5
6
7
8
9
@Singleton
// modules 定义提供依赖实例的 Module
@Component(modules = {AppModule.class, HttpModule.class})
public interface AppComponent {
ArchiApplication getContext(); // 提供App的Context

RetrofitHelper getRetrofitHelper();

}
  • 创建 AppComponent 单例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class ArchiApplication extends Application {

    public static AppComponent appComponent;

    public static AppComponent getAppComponent(){
    if (appComponent == null) {
    appComponent = DaggerAppComponent.builder()
    .appModule(new AppModule(mInstance))
    .httpModule(new HttpModule())
    .build();
    }
    return appComponent;
    }
    }

ActivityComponent

  • 自定义 ActivityScope 注解

    1
    2
    3
    4
    @Scope
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ActivityScope {
    }
  • 定义 ActivityComponent 使用 @ActivityScope 标注

    1
    2
    3
    4
    5
    6
    7
    @ActivityScope
    @Component(dependencies = AppComponent.class,modules = ActivityModule.class)
    public interface ActivityComponent {
    Activity getActivity();

    void inject(RepositoryActivity repositoryActivity);
    }
  • @ActivityScope 标注 Module 中的依赖实例提供方法

    1
    2
    3
    4
    5
    @Provides
    @ActivityScope
    public Activity provideActivity() {
    return mActivity;
    }
  • Build ActivityComponent实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public abstract class BaseActivity<T extends BasePresenter> extends SupportActivity implements BaseView {

    ...

    protected ActivityComponent getActivityComponent(){
    return DaggerActivityComponent.builder()
    // 添加依赖 component
    .appComponent(ArchiApplication.getAppComponent())
    .activityModule(new ActivityModule(this))
    .build();
    }
    }
  • 注入实例

    1
    2
    3
    4
    5
    6
    7
    8
    public class RepositoryActivity extends BaseActivity<RepositoryPresenter> implements RepositoryContract.View{
    ...
    @Override
    protected void initInject() {
    getActivityComponent().inject(this);
    }
    ...
    }

FragmentComponent

  • 自定义 FragmentComponent 注解

    1
    2
    3
    4
    @Scope
    @Retention(RetentionPolicy.RUNTIME)
    public @interface FragmentScope {
    }
  • 定义 FragmentComponent 使用 @FragmentScope 标注

    1
    2
    3
    4
    5
    6
    7
    8
    @FragmentScope
    @Component(dependencies = AppComponent.class,modules = FragmentModule.class)
    public interface FragmentComponent {

    Activity getActivity();

    void inject(MainFragment mainFragment);
    }
  • @FragmentScope 标注 Module 中的依赖实例提供方法

    1
    2
    3
    4
    5
    @Provides
    @FragmentScope
    public Activity provideActivity() {
    return fragment.getActivity();
    }
  • Build FragmentComponent

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public abstract class BaseFragment<T extends BasePresenter> extends SupportFragment implements BaseView {

    ...

    protected FragmentComponent getFragmentComponent(){
    return DaggerFragmentComponent.builder()
    // 添加依赖 component
    .appComponent(ArchiApplication.getAppComponent())
    .fragmentModule(new FragmentModule(this))
    .build();
    }
    }
  • 注入实例

    1
    2
    3
    4
    5
    6
    7
    8
    public class MainFragment extends BaseFragment<MainPresenter> implements MainContract.View {
    ...
    @Override
    protected void initInject() {
    getFragmentComponent().inject(this);
    }
    ...
    }

RetrofitHelper 注入流程

MainPresenter 和 RepositoryPresenter 的构造函数中,有一个参数为 RetrofitHelper,根据Dagger2的注入流程,我们可以知道,RetrofitHelper会优先创建注入。
在 AppComponent 中管理的 Modules 中有一个 HttpModule,该 Module 主要作用是提供网络访问实例。
我们来看一下 RetrofitHelper 的注入流程。

  • Presenter 的构造函数参数为 RetrofitHelper,所以 RetrofitHelper 会优先创建。
  • RetrofitHelper 构造函数参数为网络访问实例 RepositoriesService, UserInfoService。

    1
    2
    3
    4
    public RetrofitHelper(RepositoriesService repositoriesService, UserInfoService userInfoService){
    this.repositoriesService = repositoriesService;
    this.userInfoService = userInfoService;
    }
  • RepositoriesService 和 UserInfoService 实例由 HttpModule 提供

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    @Module
    public class HttpModule {

    /**
    * 提供builder
    * */
    @Singleton
    @Provides
    Retrofit.Builder provideRetrofitBuilder (){
    return new Retrofit.Builder();
    }

    @Singleton
    @Provides
    OkHttpClient.Builder provideOkHttpClientBuilder(){
    return new OkHttpClient.Builder();
    }



    /**
    * 提供客户端
    * */
    @Singleton
    @Provides
    @RespositoriesUrl
    Retrofit provideRepositoriesRetrofit(Retrofit.Builder builder,OkHttpClient client){
    return createRetrofit(builder, client, RepositoriesService.HOST);
    }

    @Singleton
    @Provides
    @UserInfoUrl
    Retrofit provideUserInfoRetrofit(Retrofit.Builder builder,OkHttpClient client){
    return createRetrofit(builder, client, RepositoriesService.HOST);
    }

    @Singleton
    @Provides
    OkHttpClient provideClient(OkHttpClient.Builder builder) {
    return builder.connectTimeout(60000L, TimeUnit.MILLISECONDS)
    .readTimeout(60000L, TimeUnit.MILLISECONDS)
    .writeTimeout(60000L, TimeUnit.MILLISECONDS)
    .build();
    }


    /**
    * 提供API
    * */
    @Singleton
    @Provides
    RepositoriesService provideRepositoriesService(@RespositoriesUrl Retrofit retrofit){
    return retrofit.create(RepositoriesService.class);
    }

    @Singleton
    @Provides
    UserInfoService provideUserInfoService(@UserInfoUrl Retrofit retrofit){
    return retrofit.create(UserInfoService.class);
    }

    private Retrofit createRetrofit(Retrofit.Builder builder, OkHttpClient client, String host) {
    return builder
    .baseUrl(host)
    .client(client)
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .build();
    }
    }

RetrofitHelper 完成创建后由 AppComponent 注入,为全局单一实例。

@Qualifier 使用

@Qualifier 的作用是使 Dagger2 避免依赖混乱。

  • 定义 Qualifier 以 RespositoriesUrl 为例。

    1
    2
    3
    4
    5
    @Qualifier
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    public @interface RespositoriesUrl {
    }
  • 使用 @RespositoriesUrl 标注依赖实例提供方法,该方法和其他方法的返回相同。

    1
    2
    3
    4
    5
    6
    @Singleton
    @Provides
    @RespositoriesUrl
    Retrofit provideRepositoriesRetrofit(Retrofit.Builder builder,OkHttpClient client){
    return createRetrofit(builder, client, RepositoriesService.HOST);
    }
  • 使用 @RespositoriesUrl 标注 provideRepositoriesRetrofit 的返回值

    1
    2
    3
    4
    5
    @Singleton
    @Provides
    RepositoriesService provideRepositoriesService(@RespositoriesUrl Retrofit retrofit){
    return retrofit.create(RepositoriesService.class);
    }

author @ygwang