(Dagger--A fast dependency injector for Android and Java 实例讲解)

IDE: AndroidStudio 4.2

Dagger 是一种android平台的依赖注入框架,是有一家专注于移动支付的公司,Square公司推出的库,这家公司也推出了

其他在Android开发中常用库:otto,okhttp,retrofit等等,这些在接下的博文中会一一介绍。

对Dagge的介绍,除了官方文档的介绍外,接下来的这些分析,本人觉得是比较不错的,也许在不熟悉Dagger的情况下看这

写内容,你会觉得无厘头,不知道讲什么。根据本人经验,建议先了解Dagger的使用再来看这个会对了解Dagger有比较好的效果。

如果你不喜欢看英文官方文档介绍,请参考:http://fanxu.me/post/2013-07-18

Dagger的简介,请阅读:http://www.infoq.com/cn/news/2012/10/dagger

接下来就进入正题,进行实例讲解,与官方例子一样,我这里也用煮咖啡的例子来说明,只不过官方的例子是用在Java上,这里

的例子使用Android开发来进行,并且对其也进行了改进。

首先我先说明一下这个过程,既然是煮咖啡,就要由一个加热器(Heater),加热之后要有一个倒(Pump)的过程,倒好之后才能供给人

们喝(Drink)。就这么一个简单的逻辑,你也许会和我开始一样,觉得这有什么难的,很少的代码就能搞定。是的,我们就要用这么一

个简单的事件,来看看用Dagger是怎么实现的。

首先,我们来设计Heater、Pump、Drink这三个接口,如下:

package com.example.app.dagger;/** * Created by zjb on 14-1-22. */interface Heater {    void on(); //加热器打开    void off();//加热器关闭    boolean isHot();//加热是否完毕}

package com.example.app.dagger;/** * Created by zjb on 14-1-22. */interface Pump {    void pump(); //倒咖啡    boolean isPumped();//是否倒好}

package com.example.app.dagger;/** * Created by zjb on 14-1-22. */interface Drink {    void drink(); //喝咖啡}
Ok,接口已经设计完毕,是否合理暂且不细究,接下来我们分别实现这三个接口(有用到AndroidAnnotations框架( 请看上篇博文)):

package com.example.app.dagger;import android.content.Context;import android.widget.Toast;import org.androidannotations.annotations.EBean;import org.androidannotations.annotations.RootContext;import org.androidannotations.annotations.UiThread;/** * Created by zjb on 14-1-22. */@EBeanclass ElectricHeater implements Heater {    boolean heating = false;        @RootContext    Context context;        @Override    public void on() {        heating = true;        System.out.println("-----Heating-----");        reportHeating();    }    @UiThread    void reportHeating(){        Toast.makeText(context,"Electric heater heating.....",Toast.LENGTH_LONG).show();    }    @Override    public void off() {        heating = false;    }    @Override    public boolean isHot() {        return heating;    }}

ElectricHeater是对Heater接口的实现类,@EBean,@RootContext,@UiThread是AndroidAnnotations框架中的注解。

使用@EBean注解会在编译过程中产生一个ElectricHeater子类ElectricHeater_.class, 接下来会用到。

Pump接口实现:

package com.example.app.dagger;import javax.inject.Inject;/** * Created by zjb on 14-1-22. */class Thermosiphon implements Pump {    private final Heater heater;    boolean pumped = false;    @Inject    Thermosiphon(Heater heater) {        this.heater = heater;    }    @Override    public void pump() {        if (heater.isHot()) {            System.out.println("-----Pumping-----");            pumped = true;            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    @Override    public boolean isPumped() {        return pumped;    }}


package com.example.app.dagger;import javax.inject.Inject;/** * Created by zjb on 14-1-22. */class PeopleDrink implements Drink {    private Pump pump;     @Inject     PeopleDrink(Pump pump) {        this.pump = pump;    }    @Override    public void drink(){        if(pump.isPumped()){            System.out.println("-----Drinking-----");        }        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}
三个接口已经实现完毕,对比三个实现类,有没有发现什么共同点. 是的,你会发现,三个类中都有使用@Inject来注解

他们的构造函数,这是因为Dagger要用@Inject来注解一个类的实例构造函数,当请求一个新实例的时侯,Dagger就会获取这个

参数值并调用这个构造函数。也许你不明白,没关系,继续往下看,会给出详细解释。

Dagger不仅能向上述代码那样注解构造函数,也能直接注解fields(Dagger can inject fields directly),看这个类:

package com.example.app.dagger;import javax.inject.Inject;import dagger.Lazy;/** * Created by zjb on 14-1-22. */class CoffeeMaker {    @Inject    Lazy<Heater> heater;    @Inject    Pump pump;    @Inject    Drink drink;    public void brew() {        heater.get().on();        pump.pump();        System.out.println("-----Pumped-----");        heater.get().off();        drink.drink();    }}
将Heater、Pump及Drink注入到类CoffeeMaker中,就可以直接使用并调用其方法。值得注意的是,在注解的时候Dagger

就会通过@Module中的@Provides方法调用构造函数来获得实例对象(下面马上介绍)。如果你@Inject fields却没有@Inject

构造函数,Dagger就会使用一个存在的无参构造函数,若没有@Inject构造函数,就会出错。继续看@Module

package com.example.app.dagger;import android.content.Context;import javax.inject.Singleton;import dagger.Module;import dagger.Provides;/** * Created by zjb on 14-1-22. */@Module(injects={CoffeeActivity_.class},library = true,complete = false)/*@Module(injects = {CoffeeActivity_.class},includes = {PumpModule.class,DrinkModule.class},library = true,complete = false)*/class DripCoffeeModule {    private final Context context;    public DripCoffeeModule(Context context) {        this.context = context.getApplicationContext();    }    @Provides    @Singleton    Context appliactionContext() {        return context;    }    @Provides    @Singleton    Heater provideHeater(){        return ElectricHeater_.getInstance_(appliactionContext());    }    @Provides    @Singleton    Drink provideDrink(PeopleDrink drink){        return drink;    }    @Provides    @Singleton    Pump providePump(Thermosiphon pump){        return pump;    }}

上面就是使用@Module注解的类,Dagger要求所有的@Provides必须属于一个Module.他们仅仅是一个使用@Module注解的类。

解释一下前面一句话:如果说@Inject实现了注入,那么@Provides就是实现依赖关系。@Provides方法方法的返回类型就定义了它

所满足的依赖。你也许注意到了我注释掉的@Module,这是什么意思呢?是这样的,假如我这里将providesDrink方法删除,我可以

另建一个DrinkModule.java文件,由于所有的@Provides必须属于一个Module,所以必须将DrinkModule类includes进来:

package com.example.app.dagger;import dagger.Module;/** * Created by zjb on 14-1-22. */@Module(library = true,complete = false)public class DrinkModule {    @Provides    @Singleton    Drink provideDrink(PeopleDrink drink){        return drink;    }}
(@Module后的library和complete是什么意思这里先不说)

至此,Dagger中的三个重要annotation已经全部涉及到了,那么它是如何管理这些依赖关系的呢?继续往下看:

package com.example.app.dagger;import android.app.Application;import org.androidannotations.annotations.EApplication;import dagger.ObjectGraph;/** * Created by zjb on 14-1-22. */@EApplicationpublic class CoffeeApplication extends Application {    private ObjectGraph objectGraph;    @Override    public void onCreate() {        super.onCreate();        objectGraph = ObjectGraph.create(new DripCoffeeModule(this));    }    public ObjectGraph getObjectGraph() {        return objectGraph;    }}
上边提到,Dagger是通过什么管理或者组织依赖关系的呢,就是通过ObjectGraph(对象图表)。

最后的主程序:在节面中就一个按钮来触发整个过程

package com.example.app.dagger;import android.app.Activity;import android.widget.Toast;import com.example.app.R;import org.androidannotations.annotations.AfterInject;import org.androidannotations.annotations.App;import org.androidannotations.annotations.Background;import org.androidannotations.annotations.Click;import org.androidannotations.annotations.EActivity;import org.androidannotations.annotations.UiThread;import javax.inject.Inject;import dagger.ObjectGraph;/** * Created by zjb on 14-1-22. */@EActivity(R.layout.coffee)public class CoffeeActivity extends Activity {    @App    CoffeeApplication coffeeApplication;    @Inject    CoffeeMaker maker;    @AfterInject    void daggerInject(){        ObjectGraph objectGraph = coffeeApplication.getObjectGraph();        objectGraph.inject(this);    }    @Click(R.id.coffeeClick)    @Background    void coffeeClicked(){        maker.brew();        coffeeBrew();    }    @UiThread    void coffeeBrew(){        Toast.makeText(this,"Coffee has been pumped...",Toast.LENGTH_LONG).show();    }}

程序运行的结果:

com.example.app I/System.out﹕ -----Heating-----com.example.app I/System.out﹕ -----Pumping-----com.example.app I/System.out﹕ -----Pumped-----com.example.app I/System.out﹕ -----Drinking-----

使用Dagger,我们能够很好的实现依赖关系,也能更清楚的看到我们的代码在做些事情,能够清晰地显示出各部分的

逻辑关系,通过下面这张图,我们能够很清楚的看到它的每一步操作:


好了,Dagger呢就介绍到这里,源码这次就先不上传了,等到介绍完Otto之后,我会抽空上传到资源,供大家下载学习。

内容细节说的不全请见谅、指教。如果你对使用dagger有兴趣也欢迎一起讨论、学习。这是春节前最后一篇文章了,祝大家

抢到一张好票,马上有钱、有对象!

注:文章原创 转载请注明出处:CSDN 菜鸟的成长史

附:

Demo 下载

Jake Warhton的Dagger ppt 下载资源




更多相关文章

  1. Android(安卓)Watchdog框架看门狗解析、死锁应用与改造(下)
  2. 浏览Butter Knife源码收获
  3. Android之解决开启热点后跳转页面不稳定问题
  4. android webView调用js函数的几种方法
  5. Android(安卓)studio 的安装
  6. android IPC通信机制中BBinder与BpBinder的区别
  7. Android的存储系统—Vold与MountService分析(三)
  8. Android(安卓)VelocityTracker简介
  9. Android使用ListView构造复杂界面,响应点击事件,通过Intent跳转act

随机推荐

  1. Android中的dispatchTouchEvent()、onInt
  2. Android关机界面代码
  3. Android签名制作apk
  4. Failure [INSTALL_FAILED_TEST_ONLY: ins
  5. 个人帐号密码信息管理(PAPIM)软件构想
  6. apk分享: Android应用更换皮肤功能的实现
  7. android volatile的使用
  8. android > android 发布各大市场
  9. Android Junit 单元测试步骤
  10. gson使用在android使用例子