依赖注入框架-dragger2

本文转载自:https://github.com/EvilBT/-Dagger2Demo

Dagger2 是一款使用在JavaAndroid上的依赖注入的一个类库,用来解耦的。

简单使用@inject:

配置信息

使用Android Studio 创建一个新的项目,在Project build.gradle文件添加以下内容:

buildscript {
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.2.4'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

并在Module下的build.gradle添加以下内容:

apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'me.tatarka.retrolambda'

//将jdk版本设置成1.8版本
android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
compile 'com.google.dagger:dagger:2.6'
	apt 'com.google.dagger:dagger-compiler:2.6'
    provided 'org.glassfish:javax.annotation:10.0-b28'
}

这样就基本完全了Dagger2的配置环境(顺便也配置了支持lambda表达式)。

创建一个javabean类,如下:

public class Poetry {
    private String mPemo;
    // 用Inject标记构造函数,表示用它来注入到目标对象中去
    @Inject
    public Poetry() {
        mPemo = "你看那朵云,像不像你欠我的那200块钱";
    }
    public String getPemo() {
        return mPemo;
    }
}

此时这样子在MainActivity中的mPoetry对象是无法被注入的,因为MainActivity不知道去哪里找到它的实例去注入生成,这时我们需要一个连接器Component,让上面这两个类产生联系:

//用@Component表示这个接口是一个连接器,能用@Component注解的只能是interface或者抽象类
@Component
public interface MainComponent {
    /**
     * 需要用到这个连接器的对象,就是这个对象里面有需要注入的属性(被标记为@Inject的属性)
     * 这里inject表示注入的意思,这个方法名可以随意更改,但建议就用inject即可。
     */
    void inject(MainActivity activity);
}

运行一遍,AS中会根据我们写的连接类MainComponent来生成一些类



MainActivity中注入javabean类

如果不等AS生成上述源文件,使用DaggerMainComponent注入javabean就会报错:

public class MainActivity extends AppCompatActivity {
    //添加@Inject注解,表示这个mPoetry是需要注入的
    @Inject
    Poetry mPoetry;
    @InjectView(R.id.tv_poetry)
    TextView tvPoetry;

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

        // 使用Dagger2生成的类 生成组件进行构造,并注入,注入完成后mPoetry才不为空
        DaggerMainComponent.builder()
                .build()
                .inject(this);

        tvPoetry.setText(mPoetry.getPemo());
    }
}

运行结果如下:


上面MainActivity中的Poetry实例并不直接由MainActivity类创建,而是由MainActivityComponent类注入生成实例。以上就是一个简单的Dagger2示例。


@Module

依赖moudle对象

有时候我们并不能直接在构造函数里面添加@Inject注解,或者类中存在多个构造函数时,@Inject也只能注解其中一个构造函数,不能注解多个构造函数,这里是会产生歧义性,因为Dagger2无法确认调用哪一个构造函数来生成例的实例对象。另外一种情况是我们在项目中引用第三方类库时,也是无法直接在类构造函数中添加@Inject注解的,所以我们需要用到@Module注解了。 @Module是用来生产实例来注入对象的,它类似一个工厂,集中创建要注入的类的对象实例。下面我们引用一下Gson库来看看@Module是怎么使用的,创建MainModule类:

添加Gson依赖:

compile 'com.google.code.gson:gson:2.2.4'


@Module //@Module注解表示这个类提供生成一些实例用于注入
public class MainModule {
    /**
     * @return 返回注入对象
     * @Provides 注解表示这个方法是用来创建某个实例对象的,这里我们创建返回Gson对象
     * 方法名随便,一般用provideXXX结构
     */
    @Provides
    public Gson provideGson() {
        return new Gson();
    }
}

加完这个类后,我们要与之前写的类产生关联,不然谁知道你这里提供了生成Gson实例的方法啊。修改MainCompontent

@Component(modules = MainModule.class)
public interface MainComponent {

    /**
     * 需要用到这个连接器的对象,就是这个对象里面有需要注入的属性被标记为@Inject的属性)
     * 这里inject表示注入的意思,这个方法名可以随意更改,但建议就用inject即可。
     */
    void inject(MainActivity activity);
}

MainActivity里注入Gson实例

public class MainActivity extends AppCompatActivity {
    //添加@Inject注解,表示这个mPoetry是需要注入的
    @Inject
    Poetry mPoetry;
    @Inject
    Gson mGson;

    @InjectView(R.id.tv_poetry)
    TextView tvPoetry;

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

        // 使用Dagger2生成的类 生成组件进行构造,并注入,注入完成后mPoetry才不为空
        DaggerMainComponent.builder()
                .build()
                .inject(this);
//        tvPoetry.setText(mPoetry.getPemo());
        String json = mGson.toJson(mPoetry);
        tvPoetry.setText(json);
    }
}

运行结果:

Component可以依赖多个Module对象.

以上的构造方法与生成方法都是无参生成实例的,如果我们带参数应该怎么做了?我们创建多一个PoetryModule用于提供Poetry实例:

@Module
public class PoetryModule {
    // 这个方法需要一个String参数,在Dagger2注入中,这些参数也是注入形式的,也就是
    // 要有其他对方提供参数poems的生成,不然会造成编译出错
    @Provides
    public Poetry providePoetry(String poems){
        return new Poetry(poems);//注意要同步在Poetry中生成有参构造
    }
    // 这里提供了一个生成String的方法,在这个Module里生成Poetry实例时,会查找到这里
    // 可以为上面提供String类型的参数
    @Provides
    public String providePoems(){
        return "只有意志坚强的人,才能到达彼岸";
    }
}

修改MainComponent依赖:

@Component(modules = {MainModule.class, PoetryModule.class})
public interface MainComponent {

    /**
     * 需要用到这个连接器的对象,就是这个对象里面有需要注入的属性被标记为@Inject的属性)
     * 这里inject表示注入的意思,这个方法名可以随意更改,但建议就用inject即可。
     */
    void inject(MainActivity activity);
}

运行结果如下:



细心的同学就会发现了,我们提供了两个生成Poetry实例的方法,一个是在Poetry类的构造函数时候用@Inject提供的实例创建方法,一个是在PoetryModule中的@Privodes注解的providePoetry方法

而在上面的运行结果中我们发现是调用了PoetryModule提供的方法,这里就要说明一下优先级的问题,在上面这种既在构造函数中用@Inject提供注入来源,也在@Module中用@Privodes注解提供注入来源的,Dagger2是先从@Privodes查找类实例,如果找到了就用@Module提供的方法来创建类实例,如果没有就从构造函数里用@Inject注解的生成类实例,如果二者都没有,则报错

简而言之,就是@Module的优先级高于@Inject

另外这里还要说明一点,在providePoetry(String)方法中,String这个参数也是要注入提供的,必须也要有在同一个连接器里面有提供,其中在构建类实例的时候,会按照以下顺序执行:

1.Module中查找类实例创建方法

2.Module中存在创建方法,则看此创建方法有没有参数

·如果有参数,这些参数也是由Component提供的,返回步骤1逐一生成参数类实例,最后再生成最终类实例

·如果无参数,则直接由这个方法生成最终类实例

3.Module中没有创建方法,则从构造函数里面找那个用@Inject注解的构造函数

·如果该构造函数有参数,则也是返回到步骤1逐一生成参数类实例,最后调用该构造函数生成类实例

·如果该构造函数无参数,则直接调用该构造函数生成类实例

以上就是一次注入生成类实例的生成步骤。


友情提示:其他注解方式详解和demo下载地址请参考本文转载出处:https://github.com/EvilBT/-Dagger2Demo



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值