吃火锅版Dagger2

来源:互联网 发布:python 爬虫 股票数据 编辑:程序博客网 时间:2024/06/08 10:13

前言 、去吃火锅了

1.先定义好4个类:Meat.Vegetable,Seafood,Soup

2.定义Hotpat类,里面有个方法叫makeDinner(),这个方法需要上面的4个参数,这4个参数在Hotpot构造函数中创建.

public class Meat {    public Meat(){        KLog.d("肉类");    }}
public class Seafood {    public Seafood() {        KLog.d("海鲜");    }}
public class Vegetable {    public Vegetable() {        KLog.d("蔬菜");    }}
public class Soup {    String spicy;//辣的    public Soup() {        KLog.d("清淡的锅底");    }    public Soup(String spicy) {        this.spicy = spicy;        KLog.d("加辣的锅底");    }}
public class Hotpot {    private final Soup soup;    private final Meat meat;    private final Vegetable vegetable;    private final Seafood seafood;    public Hotpot() {        soup = new Soup();        meat = new Meat();        vegetable = new Vegetable();        seafood = new Seafood();        makeDinner(soup,meat,vegetable,seafood);    }    private void makeDinner(Soup soup, Meat meat, Vegetable vegetable, Seafood seafood) {        KLog.d("吃火锅了" );    }}

简单易懂的写法,火锅制作出来了。

一、我们来看看用Dagger2的写法。

按照国际惯例,先给出配置:

  compile 'com.google.dagger:dagger:2.+'  annotationProcessor 'com.google.dagger:dagger-compiler:2.+'
  1. 增加一个类HotpotModule

首先声明:前面写的四个被依赖的类(Soup、Meat、 Vegetable、Seafood),不用做任何改动

下面要用到两个关键的注解@Module、@Provides

@Modulepublic class HotpotModule {    @Provides    public  Meat  provideMeat(){        return  new Meat();    }    // 返回值(被依赖的类类型)    // 方法名(provideXxx必须以provide开头,后面随意)    @Provides    public  Soup  provideSoup(){        return  new Soup();    }    @Provides    public  Vegetable  provideVegetable(){        return  new Vegetable();    }    @Provides    public  Seafood  provideSeafood(){        return  new Seafood();    }}

2.增加一个接口HotpotComponent

@Component(modules = {HotpotModule.class})public interface HotpotComponent {    //注意:下面这三个方法,返回值必须是从上面指定的依赖库HotpotModule.class中取得的对象    //注意:而方法名不一致也行,但是方便阅读,建议一致,因为它主要是根据返回值类型来找依赖的    //★注意:下面这三个方法也可以不写,但是如果要写,就按照这个格式来    //但是当Component要被别的Component依赖时,    //这里就必须写这个方法,不写代表不向别的Component暴露此依赖    Meat  provideMeat();    Soup provideSoup();    Vegetable  prorideVegetable();    Seafood  provideSeafood();    //注意:下面的这个方法,表示要将以上的四个依赖注入到某个类中    //这里我们把上面的三个依赖注入到Hotpot中    void inject(Hotpot  hotpot);}
  1. 重写Hotpat
public class Hotpot {    //不能有修饰符    @Inject Soup soup;    @Inject Meat meat;    @Inject Vegetable vegetable;    @Inject Seafood seafood;    public Hotpot() {        // DaggerHotpotComponent编译时才会产生这个类,        // 所以编译前这里报错不要着急(或者现在你先build一下)        DaggerHotpotComponent.builder()                .hotpotModule(new HotpotModule())                .build()                .inject(this);        makeDinner(soup,meat,vegetable,seafood);    }    private void makeDinner(Soup soup, Meat meat, Vegetable vegetable, Seafood seafood) {        KLog.d("吃火锅了" );    }}

测试:

12-25 13:59:57.545 6206-6206/com.example.myapplication D/lzx: [ (Soup.java:14)#<init> ] 清淡的锅底12-25 13:59:57.545 6206-6206/com.example.myapplication D/lzx: [ (Meat.java:12)#<init> ] 肉类12-25 13:59:57.545 6206-6206/com.example.myapplication D/lzx: [ (Vegetable.java:12)#<init> ] 蔬菜12-25 13:59:57.546 6206-6206/com.example.myapplication D/lzx: [ (Seafood.java:12)#<init> ] 海鲜12-25 13:59:57.546 6206-6206/com.example.myapplication D/lzx: [ (Hotpot.java:30)#makeDinner ] 吃火锅了

二、带参数怎么办

如果被依赖类的构造函数带有参数,要把这个参数的类型也管理起来

吃火锅怎能没有啤酒Beer呢,但是Beer的构造函数里需要传入一个Cup杯子,那么如何注入这个Beer呢

1.新增两个类

public class Cup {    public Cup() {        KLog.d("酒杯");    }}
public class Beer {    Cup cup;    public Beer(Cup cup) {        this.cup = cup;        KLog.d("酒杯里的啤酒");    }}

2.修改HotpotModule里的依赖

@Modulepublic class HotpotModule {    ...    //引入构造函数带参数的依赖    @Provides    public   Beer  provideBeer(Cup  cup){        return  new Beer(cup);    }    @Provides    public Cup  provideCup(){        return  new Cup();    }}    

3.修改Component

@Component(modules = {HotpotModule.class})public interface HotpotComponent {  //Beer provideBeer(Cup cup);//★注意:这里千万不能带参数,否则报错    Beer  provideBeer();    Cup  provideCup();    //注意:下面的这个方法,表示要将以上的四个依赖注入到某个类中    //这里我们把上面的三个依赖注入到Hotpot中    void inject(Hotpot  hotpot);}

4.在目标类Hotpot里注入依赖

public class Hotpot {    //不能有修饰符    @Inject Soup soup;    @Inject Meat meat;    @Inject Vegetable vegetable;    @Inject Seafood seafood;    @Inject Beer  beer;    //@Inject Cup  cup; //如果需要用到Cup,这里才需要注入    public Hotpot() {        // DaggerHotpotComponent编译时才会产生这个类,        // 所以编译前这里报错不要着急(或者现在你先build一下)        DaggerHotpotComponent.builder()                .hotpotModule(new HotpotModule())                .build()                .inject(this);            makeDinner(soup, meat, vegetable, seafood, beer);    }    private void makeDinner(Soup soup, Meat meat, Vegetable vegetable, Seafood seafood, Beer beer) {        KLog.d("吃火锅配啤酒");    }}

测试:

12-25 14:39:04.573 7496-7496/com.example.myapplication D/lzx: [ (Soup.java:14)#<init> ] 清淡的锅底12-25 14:39:04.573 7496-7496/com.example.myapplication D/lzx: [ (Meat.java:12)#<init> ] 肉类12-25 14:39:04.573 7496-7496/com.example.myapplication D/lzx: [ (Vegetable.java:12)#<init> ] 蔬菜12-25 14:39:04.573 7496-7496/com.example.myapplication D/lzx: [ (Seafood.java:12)#<init> ] 海鲜12-25 14:39:04.573 7496-7496/com.example.myapplication D/lzx: [ (Cup.java:12)#<init> ] 酒杯12-25 14:39:04.573 7496-7496/com.example.myapplication D/lzx: [ (Beer.java:14)#<init> ] 酒杯里的啤酒12-25 14:39:04.574 7496-7496/com.example.myapplication D/lzx: [ (Hotpot.java:32)#makeDinner ] 吃火锅配啤酒

三、有多个构造函数,怎么办

其实在前面的Soup类中已经设置了埋点,我们把汤底分成清淡的、辛辣的 。我们可以用Dagger提供的@Qualifier限定符来解决这个问题。

@Named(“String”)也能解决这个问题,只不过,传递的值只能是字符串,用@Qualifier更灵活一点

1.自己定义限定符,区分是哪个构造函数的

/** * 自定义一个限定符 */@Qualifier//限定符@Documented@Retention(RetentionPolicy.RUNTIME)public @interface Type {    String value() default "";//默认值为""}
  1. 修改HotpotModeule,使用限定符@Type来区分不同的构造函数new出来的对象。
@Modulepublic class HotpotModule {    ...    @Type("normal")    @Provides    public Soup provideNormalSoup() {        return new Soup();    }    @Type("spicy")    @Provides    public Soup provideSpicySoup(String spicy) {        return new Soup(spicy);    }    //由于我们的Soup构造函数里使用了String,所以这里要管理这个String(★否则报错)    //int等基本数据类型是不需要这样做的    @Provides    public String provideString(){        return new String();    }}

3.修改HotpotComponent

@Component(modules = {HotpotModule.class})public interface HotpotComponent {    ...    @Type("normal")    Soup provideNormalSoup();    @Type("spicy")    Soup provideSpicySoup();    String provideString();}

4.在目标类Hotpot里注入Soup依赖,我们要分别注入两个构造函数new出的对象

public class Hotpot {    //不能有修饰符    @Inject    @Type("normal")    Soup normalSoup;    @Inject    @Type("spicy")    Soup spicySoup;    @Inject    Meat meat;    @Inject    Vegetable vegetable;    @Inject    Seafood seafood;    @Inject    Beer beer;    //@Inject Cup  cup; //如果需要用到Cup,这里才需要注入    public Hotpot() {        // DaggerHotpotComponent编译时才会产生这个类,        // 所以编译前这里报错不要着急(或者现在你先build一下)        DaggerHotpotComponent.builder()                .hotpotModule(new HotpotModule())                .build()                .inject(this);        makeDinner(normalSoup ,spicySoup, meat, vegetable, seafood, beer);    }    private void makeDinner(Soup soup, Soup  spicySoup, Meat meat, Vegetable vegetable, Seafood seafood, Beer beer) {        KLog.d("吃鸳鸯火锅配啤酒");    }}

测试:

12-25 15:27:38.117 8880-8880/com.example.myapplication D/lzx: [ (Soup.java:14)#<init> ] 清淡的锅底12-25 15:27:38.117 8880-8880/com.example.myapplication D/lzx: [ (Soup.java:21)#<init> ] 加辣的锅底12-25 15:27:38.117 8880-8880/com.example.myapplication D/lzx: [ (Meat.java:12)#<init> ] 肉类12-25 15:27:38.118 8880-8880/com.example.myapplication D/lzx: [ (Vegetable.java:12)#<init> ] 蔬菜12-25 15:27:38.118 8880-8880/com.example.myapplication D/lzx: [ (Seafood.java:12)#<init> ] 海鲜12-25 15:27:38.118 8880-8880/com.example.myapplication D/lzx: [ (Cup.java:12)#<init> ] 酒杯12-25 15:27:38.118 8880-8880/com.example.myapplication D/lzx: [ (Beer.java:14)#<init> ] 酒杯里的啤酒12-25 15:27:38.118 8880-8880/com.example.myapplication D/lzx: [ (Hotpot.java:46)#makeDinner ] 吃鸳鸯火锅配啤酒

四、想要单例模式怎么办

1.在HotpotModule里,在provideXXX方法前添加@Singleton即可:

@Modulepublic class HotpotModule {    @Singleton    @Provides    public Meat provideMeat() {        return new Meat();    }    ...}

2.在HotpotComponent里,在接口上添加@Singleton 注释 即可

@Singleton //注意是在接口上添加,注意位置@Component(modules = {HotpotModule.class})public interface HotpotComponent {    ...}

3.Hotpot类不变,测试:

public class Hotpot {   @Inject    Meat meat;    @Inject    Meat meat2;    ...    private void makeDinner(Soup soup, Soup  spicySoup, Meat meat, Vegetable vegetable, Seafood seafood, Beer beer) {        KLog.d("吃鸳鸯火锅配啤酒");        KLog.d("meat:"+meat.toString()+",meat2:"+meat2.toString());    }}

结果证实是单例的!

12-25 15:37:12.738 9148-9148/com.example.myapplication D/lzx: [ (Hotpot.java:50)#makeDinner ] meat:com.example.myapplication.hot_pot.Meat@7513d90,meat2:com.example.myapplication.hot_pot.Meat@7513d90

五、 @Scope注解

dagger2中的Singleton其实就是Scope,可以查看Dagger2源码中Singleton的定义:

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

自定义的@Scope:

@Documented@Scope@Retention(RetentionPolicy.RUNTIME)public @interface ApplicationScoped {}

Dagger2中@Singleton和自己定义的@ApplicationScoped代码上并没有什么区别,那为什么还要这么做呢? 是因为Dagger2需要保证Component和Module是匹配的,就需要用到这个注解。

那它是怎么做到单例的呢?查看DaggerXXXComponent中的initialize()方法,有@Scope类注解的@Provider生成的代码,外层多了一层DoubleCheck.provider(…);没有@Scope类注解的则是直接create一个新的实例。

  private void initialize(final Builder builder) {    this.provideMeatProvider =        DoubleCheck.provider(HotpotModule_ProvideMeatFactory.create(builder.hotpotModule));    this.hotpotModule = builder.hotpotModule;  }

简单来说就是加了@Scope的Provider,Dagger会缓存一个实例在Dagger…Component中,在Dagger…Component中保持单例,缓存的provide跟随Dagger…Component的生命周期,Dagger…Component被销毁时,provider也被销毁,这就是局部单例的概念,假如你的Dagger…Component是在你应用的application中(因为Application只实例化一次!一次!一次!),则就形成了全局单例。

最面我再来介绍Component之间的依赖关系。

六、Component之间的依赖

继续回到吃火锅的剧情:吃完火锅后好需要吃些水果助消化。假如这个水果的依赖体系已经完成了(商家早就准备好的),现在火锅需要这个体系的一个对象作为依赖。这个水果的体系如下:

public class Fruit {    public Fruit() {        KLog.d("饭后水果");    }}
@Modulepublic class FruitModule {    @Provides    public  Fruit  provideFruit(){        return  new Fruit();    }}
@Component(modules = {FruitModule.class})public interface FruitComponent {    // ★前面说过这里的这个方法是可以不写的,    // 但是,如果你想让别的Component依赖这个Component,    // 就必须写,不写这个方法,就意味着没有向外界,暴露这个依赖    Fruit provideFruit();    //void inject(Object o);//这里的水果并没有想注入到那个类中,可以不写inject方法}

那么FruitComponent和HotpotComponent是怎么联系起来的呢?

@Component(modules = {HotpotModule.class},dependencies = {FruitComponent.class})//引入FruitComponentpublic interface HotpotComponent {    //其他的代码不改动}

在Hotpot注入依赖。

public class Hotpot {    ...    @Inject    Fruit fruit;     public Hotpot() {            // DaggerHotpotComponent编译时才会产生这个类,            // 所以编译前这里报错不要着急(或者现在你先build一下)            //必须先执行这个            FruitComponent fruitComponent = DaggerFruitComponent.builder().fruitModule(new FruitModule()).build();            DaggerHotpotComponent.builder()                    .hotpotModule(new HotpotModule())                    .fruitComponent(fruitComponent)  // 在这里通过传入“fruitComponent(fruitComponent)”构建HotpotComponent,                    .build()                    .inject(this);            makeDinner(normalSoup, spicySoup, meat, vegetable, seafood, beer, fruit);        }        private void makeDinner(Soup soup, Soup spicySoup, Meat meat, Vegetable vegetable, Seafood seafood, Beer beer, Fruit fruit) {            KLog.d("吃鸳鸯火锅配啤酒");            KLog.d("吃饭后还有水果吃哦");        }}

测试:

12-25 17:34:58.026 12142-12142/com.example.myapplication D/lzx: [ (Hotpot.java:57)#makeDinner ] 吃鸳鸯火锅配啤酒12-25 17:34:58.026 12142-12142/com.example.myapplication D/lzx: [ (Hotpot.java:58)#makeDinner ] 吃饭后还有水果吃哦

这次火锅盛宴结束,全剧终~~~~

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 墓王之王第二季 墓王之王观看顺序 墓王之王系列先后顺序 墓王之王寒铁斗全集免费看 墓王之王一共几部先后顺序 高王经 姓王名进不知在此经 经开万达孩子王 地藏王经念诵 桂林十里画廊图片 桂林十里画廊门票 十问歌 十悲伤孝歌 十问歌诀 中医十问歌 十问歌详解 十目所视 一目十行的意思 十目一行 目视 我的武魂是神兽 燕家十三少 十神表 神墨教育学员收费一览表 神燕轮胎价格表 欧神诺地砖价格表 星月神防盗门价格表 神都夜行录赠礼一览表 拳皇2002八神出招表 神将防盗门价格一览表 谷神收割机报价表 十秒 十秒打领带 松竹斋 衙斋卧听萧萧竹全诗译文 潍坊十笏园附近住宿 十米布 十米粥是哪十种米 十米粥 化十浪仙魔同修 十怎么组词 十组词大全