Annotation注解APT(四):依赖注入框架Dagger

本文详细介绍了Android中Dagger框架的使用,包括Android Studio的配置、注入的基本步骤、@Module和@Provides注解的应用,以及@Singleton、@Qualifier和自定义Scope的深入理解,展示了依赖注入在不同场景下的实现。
摘要由CSDN通过智能技术生成

引言
通过前面的(http://blog.csdn.net/xuewend/article/details/73511128)文章,知道了注解的作用,其中一种就是做依赖注入,dagger是依赖注入的一种框架,那么如何来使用dagger框架呢?

Android Studio中的配置
top build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'

        //添加apt插件
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

app build.gradle

//添加apt注解插件
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha7'
    testCompile 'junit:junit:4.12'

    //添加dagger依赖的库,当前版本为2.4
    compile 'com.google.dagger:dagger:2.4'
    apt 'com.google.dagger:dagger-compiler:2.4'
}

实例

package com.example.fishmov.daggerdemo;

import javax.inject.Inject;

/**
 * Created by fishmov on 17-6-21.
 */

public class People {
    private String name = "";

    @Inject
    public People() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.example.fishmov.daggerdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "fish---";

    @Inject
    People people;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "onCreate: " + people);

    }
}

直接运行,结果为:

06-21 15:35:36.818 26506-26506/com.example.fishmov.daggerdemo I/fish—: onCreate: null

因为我们目前的@Inject只是一个注解,并没有解析器来解析它,所以加不加一样,people没有初始化当然为空.

我们的目的是通过dagger框架在MainActivity自动注入依赖的People实例,要实现这个还需要一个桥梁Componet,通过Componet来注入:

package com.example.fishmov.daggerdemo;

import dagger.Component;

/**
 * Created by fishmov on 17-6-21.
 */

@Component
public interface MainComponet {

    //定义注入的方法,表示支持对某个类的注入
    void inject(MainActivity activity);
}

记得rebuild一下,将自动生成Dagger+MainComponet一个类

package com.example.fishmov.daggerdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "fish---";

    @Inject
    People people;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "onCreate: " + people);

        DaggerMainComponet.builder().build().inject(this);

        Log.i(TAG, "onCreate: " + people);

    }
}

直接运行,结果为:

com.example.fishmov.daggerdemo I/fish—: onCreate: null
com.example.fishmov.daggerdemo I/fish—: onCreate: com.example.fishmov.daggerdemo.People@9af3aad

可以看到,调用dagger注入后,people实例化了一个对象.这种注入方式是最基本的注入方式,
然而这并没有什么卵用.
通过这种方式注入,需要在类的构造方法中添加@Inject注解,有时候我们无法修改别人的构造方法的时候,要如何使用注入呢?这个时候就需要@Module@Provides注解了.

实例

package com.example.fishmov.daggerdemo;

import javax.inject.Inject;

/**
 * Created by fishmov on 17-6-21.
 */

public class People {
    private String name = "";


    public People() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.example.fishmov.daggerdemo;

import dagger.Component;

/**
 * Created by fishmov on 17-6-21.
 */

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

    //定义注入的方法,表示支持对某个类的注入
    void inject(MainActivity activity);
}
package com.example.fishmov.daggerdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "fish---";

    @Inject
    People people;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "onCreate: " + people);

        DaggerMainComponet.builder().mainModule(new MainModule()).build().inject(this);

        Log.i(TAG, "onCreate: " + people);

    }
}

直接运行输出:

I/fish—: onCreate: null
I/fish—: onCreate: com.example.fishmov.daggerdemo.People@9af3aad

整个过程可以归纳为以下步骤:

  1. Activity中通过DaggerXXXComponent的Inject()触发注入过程;
  2. Dagger在Activity中搜索用@Inject标注的变量,说明该对象需要被注入;
  3. 去Component中注册的Module中搜索注入类;
  4. 在Module中搜索返回值为注入类的方法,执行并拿到注入类对象,从而完成注入过程;
  5. 如果在Module中没有搜索到提供目标类注入的方法,则在工程中搜索目标类;
  6. 找到需要注入对象后,寻找该对象中用@Inject标识的构造方法,完成自动创建过程.

如果People类的构造方法需要参数怎么办?如下:

package com.example.fishmov.daggerdemo;

import javax.inject.Inject;

/**
 * Created by fishmov on 17-6-21.
 */

public class People {
    private String name = "";


    public People(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.example.fishmov.daggerdemo;

import dagger.Module;
import dagger.Provides;

/**
 * Created by fishmov on 17-6-21.
 */
@Module   //提供依赖对象的实例
public class MainModule {

    @Provides  // 关键字,标明该方法提供依赖对象
    People providerPerson(String name){
        //提供Person对象
        return new People(name);
    }

    @Provides
    String providerName(){
        return "zhangsan";
    }

  //或者使用这种
  //@Provides  // 关键字,标明该方法提供依赖对象
   //People providerPerson(){
        //提供Person对象
    //    return new People("zhangsan");
    //}

}
package com.example.fishmov.daggerdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "fish---";

    @Inject
    People people;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "onCreate: " + people);

        DaggerMainComponet.builder().mainModule(new MainModule()).build().inject(this);

        Log.i(TAG, "onCreate: " + people.getName());

    }
}

直接运行输出:

I/fish—: onCreate: null
I/fish—: onCreate: zhangsan

如果想注入同一对象的多个实例怎么办?这个时候就需要
@Named

package com.example.fishmov.daggerdemo;

import javax.inject.Named;

import dagger.Module;
import dagger.Provides;

/**
 * Created by fishmov on 17-6-21.
 */
@Module   //提供依赖对象的实例
public class MainModule {

    @Named("a")
    @Provides  // 关键字,标明该方法提供依赖对象
    People providerPersonA(){
        //提供Person对象
        return new People("张三");
    }

    @Named("b")
    @Provides  // 关键字,标明该方法提供依赖对象
    People providerPersonB(){
        //提供Person对象
        return new People("李四");
    }

}
package com.example.fishmov.daggerdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "fish---";

    @Named("a")
    @Inject
    People peopleA;


    @Named("b")
    @Inject
    People peopleB;

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


        DaggerMainComponet.builder().mainModule(new MainModule()).build().inject(this);

        Log.i(TAG, "onCreate: " + peopleA.getName());
        Log.i(TAG, "onCreate: " + peopleB.getName());

    }
}

运行结果:

I/fish—: onCreate: 张三
I/fish—: onCreate: 李四

@Named注解表示采用使用module中的哪个provides,看看@Named的代码:

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {

    /** The name. */
    String value() default "";
}

可以看出value是String类型的,前面学过如何自定义注解(http://blog.csdn.net/xuewend/article/details/73507725),我们也可以自定义一个,来达到和@Named一样的效果,关键字段
@Qualifier

package com.example.fishmov.daggerdemo;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import javax.inject.Qualifier;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * Created by fishmov on 17-6-21.
 */
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface MType {
    int value() default -1;
}
package com.example.fishmov.daggerdemo;

import javax.inject.Named;

import dagger.Module;
import dagger.Provides;

/**
 * Created by fishmov on 17-6-21.
 */
@Module   //提供依赖对象的实例
public class MainModule {

    @MType(1)
    @Provides  // 关键字,标明该方法提供依赖对象
    People providerPersonA(){
        //提供Person对象
        return new People("张三");
    }

    @MType(2)
    @Provides  // 关键字,标明该方法提供依赖对象
    People providerPersonB(){
        //提供Person对象
        return new People("李四");
    }

}
package com.example.fishmov.daggerdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "fish---";

    @MType(1)
    @Inject
    People peopleA;


    @MType(2)
    @Inject
    People peopleB;

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


        DaggerMainComponet.builder().mainModule(new MainModule()).build().inject(this);

        Log.i(TAG, "onCreate: " + peopleA.getName());
        Log.i(TAG, "onCreate: " + peopleB.getName());

    }
}

运行结果不变.

@Singleton注解
如果我们把peopleB peopleA都注解为@MType(1)

package com.example.fishmov.daggerdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "fish---";

    @MType(1)
    @Inject
    People peopleA;


    @MType(1)
    @Inject
    People peopleB;

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


        DaggerMainComponet.builder().mainModule(new MainModule()).build().inject(this);

        Log.i(TAG, peopleA.getName() + peopleA);
        Log.i(TAG, peopleB.getName() + peopleB);

    }
}

运行效果:

I/fish—: 张三com.example.fishmov.daggerdemo.People@9af3aad
I/fish—: 张三com.example.fishmov.daggerdemo.People@24ae1e2

可以看出,名字一样,但是地址不同,如果在module中添加@Singleton

package com.example.fishmov.daggerdemo;

import javax.inject.Named;
import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

/**
 * Created by fishmov on 17-6-21.
 */
@Module   //提供依赖对象的实例
public class MainModule {

    @Singleton
    @MType(1)
    @Provides  // 关键字,标明该方法提供依赖对象
    People providerPersonA(){
        //提供Person对象
        return new People("张三");
    }

    @MType(2)
    @Provides  // 关键字,标明该方法提供依赖对象
    People providerPersonB(){
        //提供Person对象
        return new People("李四");
    }

}

同样,这里也要添加@Singleton

package com.example.fishmov.daggerdemo;

import javax.inject.Singleton;

import dagger.Component;

/**
 * Created by fishmov on 17-6-21.
 */
@Singleton
@Component(modules = MainModule.class)
public interface MainComponet {

    //定义注入的方法,表示支持对某个类的注入
    void inject(MainActivity activity);
}

MainActivity不变,直接运行输出:

I/fish—: 张三com.example.fishmov.daggerdemo.People@9af3aad
I/fish—: 张三com.example.fishmov.daggerdemo.People@9af3aad

可以看出地址一样,这就是单例.
但是单例是有作用范围的,比如:

package com.example.fishmov.daggerdemo;

import javax.inject.Singleton;

import dagger.Component;

/**
 * Created by fishmov on 17-6-21.
 */
@Singleton
@Component(modules = MainModule.class)
public interface MainComponet {

    //定义注入的方法,表示支持对某个类的注入
    void inject(MainActivity activity);
    //定义注入的方法,表示支持对某个类的注入
    void inject(MainActivity.House house);
}
package com.example.fishmov.daggerdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "fish---";

    @MType(1)
    @Inject
    People peopleA;


    @MType(1)
    @Inject
    People peopleB;

    MainModule mainModule;

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

        mainModule = new MainModule();
        DaggerMainComponet.builder().mainModule(mainModule).build().inject(this);

        Log.i(TAG, peopleA.getName() + peopleA);
        Log.i(TAG, peopleB.getName() + peopleB);
        new House();

    }


    class House{
        @MType(1)
        @Inject
        People peopleA;


        @MType(1)
        @Inject
        People peopleB;

        public House() {
            DaggerMainComponet.builder().mainModule(mainModule).build().inject(this);
            Log.i(TAG + "House", peopleA.getName() + peopleA);
            Log.i(TAG + "House", peopleB.getName() + peopleB);
        }
    }
}

结果输出:

I/fish—: 张三com.example.fishmov.daggerdemo.People@e7e1ddb
I/fish—: 张三com.example.fishmov.daggerdemo.People@e7e1ddb
I/fish—House: 张三com.example.fishmov.daggerdemo.People@b2da078
I/fish—House: 张三com.example.fishmov.daggerdemo.People@b2da078

可以看出,同一个Componet注入的地址一样,不同的地址不一样,这叫做假单例,那如何做到全局的单例呢?

package com.example.fishmov.daggerdemo;

import android.app.Application;

/**
 * Created by fishmov on 17-6-21.
 */

public class MyApplication extends Application {

    private static MainComponet mainComponet;
    @Override
    public void onCreate() {
        super.onCreate();
        mainComponet = DaggerMainComponet.builder().mainModule(new MainModule()).build();
    }

    public static MainComponet getMainComponet() {
        return mainComponet;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.fishmov.daggerdemo">

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
package com.example.fishmov.daggerdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "fish---";

    @MType(1)
    @Inject
    People peopleA;


    @MType(1)
    @Inject
    People peopleB;

    MainModule mainModule;

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


        MyApplication.getMainComponet().inject(this);

        Log.i(TAG, peopleA.getName() + peopleA);
        Log.i(TAG, peopleB.getName() + peopleB);
        new House();

    }


    class House{
        @MType(1)
        @Inject
        People peopleA;


        @MType(1)
        @Inject
        People peopleB;

        public House() {
            MyApplication.getMainComponet().inject(this);
            Log.i(TAG + "House", peopleA.getName() + peopleA);
            Log.i(TAG + "House", peopleB.getName() + peopleB);
        }
    }
}

结果输出:

I/fish—: 张三com.example.fishmov.daggerdemo.People@9af3aad
I/fish—: 张三com.example.fishmov.daggerdemo.People@9af3aad
I/fish—House: 张三com.example.fishmov.daggerdemo.People@9af3aad
I/fish—House: 张三com.example.fishmov.daggerdemo.People@9af3aad

可以看出地址一样了

@Scope注解
@Scope注解相对于@Singleton,和@Qualifier相对于@Named一样,
看源码:

@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

所以我们也可以通过@Scope自定义一个注解功能和@Singleton一样.
好了,就到这里吧,其实没有什么卵用.

参考:
http://blog.csdn.net/lylodyf/article/details/52981910?locationNum=8&fps=1
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0528/4307.html
https://wenku.baidu.com/view/9b6be73515791711cc7931b765ce0508763275cd.html?from=search

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fishmov

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值