likes
comments
collection
share

Dagger2四种使用方式

作者站长头像
站长
· 阅读数 11

1. 什么是Dagger2

Dagger2是用来解决对象之间的高度耦合的框架。介绍Dagger2四种方式实现。

Dagger2四种使用方式

具体的四种使用场景

0. 配置

app模块下的build.gradle
dependencies {
    //...其他依赖信息
    implementation 'com.google.dagger:dagger:2.44'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.44'
}

1. 第一种实现方式

自己实现的代码可以在代码的构造函数上通过@Inject修饰,实现代码注入,如下:

Dagger2四种使用方式

1. 实现细节

public class SingleInstance {
    //1. 在需要注入的地方通过`@Inject`注解进行标记。
    @Inject
    User user;

    @Inject
    public SingleInstance() {
        // 4. 关键一步是将Component注入到目标类中,在需要实现注入的地方调用由`@Component`修饰的接口生成的对应的类。名字规则为`Dagger+被@Component修饰的接口名`代码为`DaggerApplicationComponent.create().inject(this);`。
        DaggerApplicationComponent.create().inject(this);
        Log.i("TAG", "SingleInstance === " + user);
    }
}


public class User {
    //3. 需要被实例化的类其构造函数需使用`@Inject`注解进行修饰。
    @Inject
    public User() {

    }
}


@Component
public interface ApplicationComponent {
     // 2. `@Component`修饰的是一个接口,并在该接口中提供一个将对象注入到那个类的方法,方法名一般为inject,其参数为注入到的目标类的类名。如示例中注入到`MainActivity`和`SingleInstance`两个类中,则定义为`void inject(MainActivity mainActivity)`和`void inject(SingleInstance singleInstance)`。
    void inject(MainActivity activity);
    //指定将对象注入到什么位置,这里值注入到SingleInstance中
    void inject(SingleInstance activity);
}


//TODO 被注入的类
public class MainActivity extends AppCompatActivity {
    @Inject
    SingleInstance instance;
    @Inject
    User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerApplicationComponent.create().inject(this);
        Log.i("TAG", "instance == " + instance);
        Log.i("TAG", "user == " + user);
    }
}

2. 小结
  1. 该种方式适用于自定义类的实例化。具体思路如下:
  2. 在需要注入的地方通过@Inject注解进行标记。
  3. @Component修饰的是一个接口,并在该接口中提供一个将对象注入到那个类的方法,方法名一般为inject,其参数为注入到的目标类的类名。如示例中注入到MainActivitySingleInstance两个类中,则定义为void inject(MainActivity mainActivity)void inject(SingleInstance singleInstance)
  4. 需要被实例化的类其构造函数需使用@Inject注解进行修饰。
  5. 关键一步是将Component注入到目标类中,在需要实现注入的地方调用由@Component修饰的接口生成的对应的类。名字规则为Dagger+被@Component修饰的接口名代码为DaggerApplicationComponent.create().inject(this);

2. 第二种实现方式

第三方库可以Module+主Component的方式实现。该种方式解决对第三方库的初始化。

Dagger2四种使用方式

@Module
public class HttpModule {

    //TODO 在module提供实例
    @NetScope
    @Provides
    String providerUrl() {
        return "http://www.baidu.com";
    }

    @NetScope
    @Provides
    GsonConverterFactory providerGsonConverterFactory() {
        return GsonConverterFactory.create();
    }

    @NetScope
    @Provides
    RxJava2CallAdapterFactory providerRxjava2CallAdapterFactory() {
        return RxJava2CallAdapterFactory.create();
    }

    /**
     * 1. 这里可以通过作用域限制实例使用的范围,这里的作用域必须和自己的Component使用的一样。
     * 2. 一个Component只能有一个作用域修饰符。
     *
     * @return
     */
    @NetScope
    @Provides
    OkHttpClient providerOkHttpClient() {
        return new OkHttpClient.Builder()
                //TODO  这里可以添加各种拦截器
                .build();
    }

    @NetScope
    @Provides
    Retrofit providerRetrofit(String url,
                              OkHttpClient okHttpClient,
                              GsonConverterFactory gsonConverterFactory,
                              RxJava2CallAdapterFactory rxJava2CallAdapterFactory) {
        return new Retrofit.Builder()
                .baseUrl(url)
                .client(okHttpClient)
                .addConverterFactory(gsonConverterFactory)
                .addCallAdapterFactory(rxJava2CallAdapterFactory)
                .build();
    }

    @NetScope
    @Provides
    ApiService providerApiService(Retrofit retrofit) {
        return retrofit.create(ApiService.class);
    }
}



@Module
public class DaoModule {
    @Name01
    @Provides
    Student providerStudent01() {
        return new Student("tom01");
    }

    @Name02
    @Provides
    Student providerStudent02() {
        return new Student("tom02", 20);
    }

    @Named("threeParam")
    @Provides
    Student providerStudent03() {
        return new Student("tom03", 20, 1);
    }

}


//NetScope这里的直接是为了限制其作用域
@NetScope
@Component(modules = {HttpModule.class,DaoModule.class})//装载多个Module
public interface HttpComponent {
    void inject(MainActivity activity);
}

//被注入的类
public class MainActivity extends AppCompatActivity {


    @Inject
    ApiService apiService;

    @Inject
    ApiService apiService2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerHttpComponent.builder()
                .build()
                .inject(this);
        Log.i(" TAG", "apiService === " + apiService);
        Log.i(" TAG", "apiService2 === " + apiService2);

    }
}



小结
  1. 通过Module提供了创建实例的方法。这里的@NetScope用于限制了创建实例的作用域。
  2. providerRetrofit方法中的参数是由其他几个方法提供的,如果没有提供@Providers修饰的方法提供实例外,Dagger2会去找被@Inject修饰的构造方法创建实例,如果都没有提供方法参数的实例则会报错。
  3. 如果相同的类型创建不同的对象可以使用@Named注解解决.
  4. @NetScope注解用来使用限定作用域。

3. 第三种实现方式

通过多组件实现相互依赖并提供实例。

Dagger2四种使用方式

//提供了全局的组件
@Component(modules = UserModule.class)
public interface ApplicationComponent {
    User createUser();//通过这种方式需要将UserModule中的参数暴露出来,需要提供要暴露出来的相关方法。
//    HttpComponent createHttpComponent();
}

//提供基础的实例
@BaseHttpScope
@Component(modules = BaseHttpModule.class, dependencies = ApplicationComponent.class)
public interface BaseHttpComponent {
    
    //TODO 在其他子组件需要依赖时,需要将对应的方法暴露出来
    Retrofit providerRetrofit();
}



//这里依赖了BaseHttpComponent组件中提供的实例
@NetScope
@Component(modules = ApiServiceModule.class, dependencies = BaseHttpComponent.class)
public interface ApiServiceComponent {
    void inject(MainActivity activity);
}


//具体的实现注入的地方的初始化
public class MainActivity extends AppCompatActivity {

    @Inject
    ApiService apiService;

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

        DaggerApiServiceComponent.builder()
                .baseHttpComponent(DaggerBaseHttpComponent.builder()
                        .applicationComponent(DaggerApplicationComponent.create())
                        .build()).build()
                .inject(this);
        Log.i("TAG", "apiService == " + apiService);

    }
}

小结

  1. 这里需要注意的是ApiServiceComponent组件依赖BaseHttpComponent组件,BaseHttpComponent组件以来的是ApplicationComponent组件,结果就是在注入的地方如
 DaggerApiServiceComponent.builder()
                .baseHttpComponent(DaggerBaseHttpComponent.builder()
                        .applicationComponent(DaggerApplicationComponent.create())
                        .build()).build()
                .inject(this);
  1. 需要被子组件使用的实例需要在XXComponent中暴露出来,如果没有暴露出来会去找被@Inject修饰的构造方法创建实例,如果没有找到则会报错。不能提供对应的实例。

4. 第四种实现方式

跟上面多个Component提供创建实例时,如果在子组件中需要使用父组件中提供的实例,父组件需要手动暴露出提供对应实例的方法。

Dagger2四种使用方式


@Module
public class ApiServiceModule {
    //TODO 在module提供实例
    @NetScope
    @Provides
    String providerUrl() {
        return "http://www.baidu.com";
    }

    @NetScope
    @Provides
    GsonConverterFactory providerGsonConverterFactory() {
        return GsonConverterFactory.create();
    }

    @NetScope
    @Provides
    RxJava2CallAdapterFactory providerRxjava2CallAdapterFactory() {
        return RxJava2CallAdapterFactory.create();
    }

    /**
     * 1. 这里可以通过作用域限制实例使用的范围,这里的作用域必须和自己的Component使用的一样。
     * 2. 一个Component只能有一个作用域修饰符。
     *
     * @return
     */
    @NetScope
    @Provides
    OkHttpClient providerOkHttpClient() {
        return new OkHttpClient.Builder()
                //TODO  这里可以添加各种拦截器
                .build();
    }

    @NetScope
    @Provides
    Retrofit providerRetrofit(String url,
                              OkHttpClient okHttpClient,
                              GsonConverterFactory gsonConverterFactory,
                              RxJava2CallAdapterFactory rxJava2CallAdapterFactory) {
        return new Retrofit.Builder()
                .baseUrl(url)
                .client(okHttpClient)
                .addConverterFactory(gsonConverterFactory)
                .addCallAdapterFactory(rxJava2CallAdapterFactory)
                .build();
    }

    @NetScope
    @Provides
    ApiService providerApiService(Retrofit retrofit) {
        return retrofit.create(ApiService.class);
    }
}
@NetScope
@Subcomponent(modules = ApiServiceModule.class)
public interface ApiServiceComponent {
    @Subcomponent.Factory
    interface Factory {
        ApiServiceComponent create();
    }

    void inject(MainActivity activity);
}
@Module(subcomponents = ApiServiceComponent.class)
public class ApiServiceComponentModule {

}

@Component(modules = {ApiServiceComponentModule.class})
public interface ApplicationComponent {
    //这里在主组件中需要把子组件暴露出来
    ApiServiceComponent.Factory createApiServiceComponent();
}

public class MainActivity extends AppCompatActivity {

    @Inject
    ApiService apiService;

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

        DaggerApplicationComponent.create()
                .createApiServiceComponent()
                .create()
                .inject(this);
        Log.i("TAG", "apiService == " + apiService);
    }
}

小结

  1. 这里需要注意的一点是SubComponent装载到主组件中时需要使用一个Module链接。

5. 其他几个使用方法Binds和Lazy 参考demo app05


@Module
public abstract class DaoModule {
    /**
     * 这里的参数类型决定了调用哪一个实现方法
     *
     * @param impl01
     * @return
     */
    @Binds
    public abstract BInterface bindBInterface01(Impl01 impl01);


    @Provides
    static Impl01 providerBInterface01() {
        return new Impl01();
    }

    @Provides
    static Impl02 providerBInterface02() {
        return new Impl02();
    }

}

public class MainActivity extends AppCompatActivity {

    @Inject
    BInterface impl01;

    @Inject
    Lazy<BInterface> impl02;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerApplicationComponent.create()
                .inject(this);

        Log.i("TAG", "impl01 === " + impl01.getClass().getSimpleName());

        Log.i("TAG", "impl02 === " + impl02.getClass().getSimpleName());

        Log.i("TAG", "impl02 impl02.get()=== " + impl02.get().getClass().getSimpleName());
    }
}
 

dagger2参考资料

hilt参考资料

demo地址