安卓dagger2简易使用教程

1. 什么是dagger2

dagger2是一个依赖注入框架,依赖注入,我的理解是,一个类中所依赖实例变量,不在本类中直接创建,而是在其他类中赋值然后传入。

权威解释:依赖注入


2.为什么使用dagger2

dagger2设计的目的就是为了解耦合,避免了一个类中各种眼花缭乱、重复的赋值语句。


3.如何使用dagger2

dagger2使用正确步骤:导入依赖→编写代码↔rebuild工程(根据注解自动生成中间代码)→开始运行

dagger2使用官方教程:https://google.github.io/dagger/

dagger2 gitub:https://github.com/google/dagger

3.1.导入依赖

1.在gradle的buildscript下:

dependencies { ...

//添加apt插件 classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

}

2.在build.gradle中:

apply plugin: 'com.neenbedankt.android-apt'

...

dependencies {

apt 'com.google.dagger:dagger-compiler:2.4'

compile 'com.google.dagger:dagger:2.4'

//java注解 provided 'org.glassfish:javax.annotation:10.0-b28'

}

3.2.代码编写

3.2.1.Componet + Inject

Componet组件:连接目标类和赋值类的桥梁,使用@Componet注解在对应组件类的类名前标注

Inject:说明目标类属性和赋值类赋值方法的位置,使用@Inject注解在对应类的构造方法前进行标注

赋值类:

1.使用Inject来赋值,只能使用构造标注,不能使用方法标注

//正确的用法

public class IntegerProducer {

    private int num;

    @Inject 

    public IntegerProducer() {

        num = new Random().nextInt(9999);

    }

    public int produce() {

        return num;

    }

}

//错误的用法(以下用法编译不通过)

public class OtherProducer {

    @Inject

    public IntegerProducer get() {

        return new IntegerProducer();

    }

}

2.带参的构造方法,其参数应该也可以依赖注入

public class FatherProducer {

private IntegerProducer ip;

    @Inject // IntegerProducer 已经支持依赖注入,可以参照上面的例子

    public FatherProducer(IntegerProducer ip) {

    this.ip = ip;

    }

    public int produce() {

        return ip.produce();

    }

}

3.一个Inject赋值类中只能提供一个赋值构造方法,也就是说只能有一个@Inject注解标注的构造函数

桥梁:

1.使用interface定义,在接口前使用@Component注解标注

2.接口内方法必须提供与目标类绑定或者关联的方法

@Component

public interface Case01Component {

    void inject(Case01Activity activity);

}

目标类:

1.在目录类属性前使用@Inject注解

2.待注入的属性值不能用private修饰

public class Case01Activity extends AppCompatActivity {

    @Inject

    IntegerProducer ip;

    @Inject

    FatherProducer fp;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case01);

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) findViewById(R.id.line2);

        DaggerCase01Component.builder().build().inject(this);  // DaggerCase01Component是根据Component桥梁的代码,然后rebuild工程生成的

    }

    public void test(View v) {

        line1.setText(String.valueOf(ip.produce()));

        line2.setText(String.valueOf(fp.produce()));

    }

}

运行结果:


case-01

3.2.2.Component + Module

Module注解:Module的功能和Inject类似,也是用作赋值功能,使用@Module注解在Moudle类前标注

1.Module中提供赋值类的办法是,在方法上添加@Provides注解

@Module

public class Case02Module {   

     @Provides    

    public ColorPicker provideColorGreen() {        

        return new ColorPicker(Color.GREEN);    

    }

}

2.Component需与对应的Module关联起来(注:一个Component可与多个Module关联起来)

@Component(modules = Case02Module.class)

public interface Case02Component {

    void inject(Case02Activityactivity);

}

3.目标类属性依然使用@Inject标注

public class Case02Activity extends AppCompatActivity {

    @Inject

    ColorPicker cp;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case02);

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) findViewById(R.id.line2);

    }

    public void test(View v) {

        line1.setTextColor(cp.pick());

        line2.setTextColor(cp.pick());

    }

}

运行结果:


case-02


4.一个Module中对于同一种赋值类,可以使用@Named注解提供多钟赋值方法(与@Inject赋值的区别之一)

@Module

public class Case02Module {

    @Provides

    @Named("green")

    public ColorPicker provideColorGreen() {

        return new ColorPicker(Color.GREEN);

    }

    @Provides

    @Named("blue")

    public ColorPicker provideColorBlue() {

        return new ColorPicker(Color.BLUE);

    }

}


public class Case02Activity extends AppCompatActivity {

    @Inject

    @Named("green")

    ColorPicker cp1;

    @Inject

    @Named("blue")

    ColorPicker cp2;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case02);

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) finViewById(R.id.line2);

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

    }

    public void test(View v) {

        line1.setTextColor(cp1.pick());

        line2.setTextColor(cp2.pick());

    }

}

运行结果:


case-02.1


5.Module赋值和Inject赋值同时存在时,先查找Module,如果Module赋值成功,不再查找Inject注解;如果Module赋值不成功,继续查找Inject赋值

3.2.3.作用域Scope

作用域:限定赋值方法的使用范围

1.作用域如何自定义,类似于自定义注解,除此之外要加@Scope注解

@Scope

@Retention(RetentionPolicy.RUNTIME)

public @interface Color {}


@Scope

@Retention(RetentionPolicy.RUNTIME)

public @interface Content {}

2.作用域,限定了Component能使用哪些赋值方法

a)Componet和Module中赋值方法通过同一个作用域标注@Content联结起来,如何缺少Module中赋值方法的作用域,则会编译错误

@Module

public class Case03Module {

    @Content

    @Provides

    public IntegerProducer produceNum() {

        return new IntegerProducer();

    }

}

@Content

@Component(modules = Case03Module.class)

public interface Case03Component {

    void inject(Case03Activity activity);

}


b)有趣的是,Component可以同时有多个作用域,类似以下例子@Content @Color

@Module

public class Case03Module {

    @Content

    @Provides

    public IntegerProducer produceNum() {

        return new IntegerProducer();

    }

    @Color

    @Provides

    public ColorPicker produceColor() {

       return new ColorPicker(android.graphics.Color.RED);

    }

}

@Content

@Color

@Component(modules = Case03Module.class)

public interface Case03Component {

    void inject(Case03Activity activity);

}

3.不加作用域,赋值时会生成新的变量

@Component(modules = Case04Module.class)

public interface Case04Component {

    void inject(Case04Activity activity);

}

@Module

public class Case04Module {

    @Provides

    public AddressProducer provideAddress() {

        return new AddressProducer();

    }

}

public class Case04Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    @Inject

    AddressProducer ap2;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case04);

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) findViewById(R.id.line2);

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

    }

    public void test(View v) {

        line1.setText(ap1.produce());

        line2.setText(ap2.produce());

    }

}

public class AddressProducer {

    public AddressProducer() { }

    public String produce() { return this.toString();

    }

}

运行效果:


case04

4.@Singleton标注一般用来做全局单例,实质上是没有直接使赋值变量成为单例的能力,以下例子可以看出其实注入的属性值是不是同一个,取决于是否为同一个Component注入;因此要想保持全局单例,正确的做法应该是在Application或者BaseActivity基类中去初始化Component,然后在Appliaction或者基类容器缓存单例Component,然后再其他地方去注入或者联结

@Component(modules = Case05Module.class)

@Singleton

public interface Case05Component {

    void inject(Case05Activity activity);

    void inject(Case051Activity activity);

    void inject(Case052Activity activity);

    void inject(Case053Activity activity);

}

@Module

public class Case05Module {

    @Provides

    @Singleton

    public AddressProducer provideAddress() {

        return new AddressProducer();

    }

}

public class Case05Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    @Inject

    AddressProducer ap2;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case05);

        //因为是使用同一个实例化的Component注入,两个变量相等       

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) findViewById(R.id.line2);

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

    }

    public void test(View v) {

        line1.setText(ap1.produce());

        line2.setText(ap2.produce());

    }

}

public class Case051Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    private TextView line1;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case051);

    line1 = (TextView) findViewById(R.id.line1);

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

    }

    public void test(View v) {

        line1.setText(ap1.produce());

    }

}


public class App extends Application {

    private Case05Component case05Component;

    @Override

    public void onCreate() {

        super.onCreate();

        case05Component = DaggerCase05Component.builder().build();

    }

    public Case05Component getCase05Component() { return case05Component; }

}


public class Case052Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    private TextView line1;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case052);

        line1 = (TextView) findViewById(R.id.line1);

        App app = (App) getApplicationContext();

        app.getCase05Component().inject(this);

}

    public void test(View v) { line1.setText(ap1.produce()); }

}


public class Case053Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    private TextView line1;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case053);

        line1 = (TextView) findViewById(R.id.line1);

        App app = (App) getApplicationContext();

        app.getCase05Component().inject(this);

}

    public void test(View v) { line1.setText(ap1.produce()); }

}

运行效果:


case05


case05-1


case05-2


case05-3

5.自定义作用域名义上是局部作用域,实质上和@Singleton一样是没有真正的限定使用范围的功能,还是通过缓存实例化的Component来达到真正的作用域功能

@Scope

@Retention(RetentionPolicy.RUNTIME)

public @interface address {}



@Component(modules = Case06Module.class)

@address

public interface Case06Component {

    void inject(Case06Activity activity);

    void inject(Case061Activity activity);

}


@Module

public class Case06Module {

    @Provides

    @address

    public AddressProducer provideAddress() {

        return new AddressProducer();

    }

}


public class Case06Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    @Inject

    AddressProducer ap2;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case05);

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) findViewById(R.id.line2);

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

    }

    public void test(View v) {

        line1.setText(ap1.produce());

        line2.setText(ap2.produce());

    }

}


public class Case061Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    private TextView line1;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case061);

        line1 = (TextView) findViewById(R.id.line1);

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

    }

    public void test(View v) {

        line1.setText(ap1.produce());

    }

}

运行结果:


case06


End:有关dagger2的简易使用教程,暂时就介绍到这里,有时间继续补充其他使用案例和原理,如果你发现了错误,欢迎批评与指正。

Demo 下载地址:demo

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容