Android 依赖注入:Dagger 实例讲解(Demo下载)

 

Android 依赖注入:Dagger 实例讲解(Demo下载)

分类: android   6451人阅读  评论(3)  收藏  举报

(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这三个接口,如下:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2.   
  3. /** 
  4.  * Created by zjb on 14-1-22. 
  5.  */  
  6. interface Heater {  
  7.     void on(); //加热器打开  
  8.     void off();//加热器关闭  
  9.     boolean isHot();//加热是否完毕  
  10. }  

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2.   
  3. /** 
  4.  * Created by zjb on 14-1-22. 
  5.  */  
  6. interface Pump {  
  7.     void pump(); //倒咖啡  
  8.     boolean isPumped();//是否倒好  
  9. }  

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2.   
  3. /** 
  4.  * Created by zjb on 14-1-22. 
  5.  */  
  6. interface Drink {  
  7.     void drink(); //喝咖啡  
  8. }  
Ok,接口已经设计完毕,是否合理暂且不细究,接下来我们分别实现这三个接口(有用到AndroidAnnotations框架( 请看上篇博文)):

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2. import android.content.Context;  
  3. import android.widget.Toast;  
  4. import org.androidannotations.annotations.EBean;  
  5. import org.androidannotations.annotations.RootContext;  
  6. import org.androidannotations.annotations.UiThread;  
  7.   
  8. /** 
  9.  * Created by zjb on 14-1-22. 
  10.  */  
  11. @EBean  
  12. class ElectricHeater implements Heater {  
  13.     boolean heating = false;  
  14.       
  15.     @RootContext  
  16.     Context context;  
  17.       
  18.     @Override  
  19.     public void on() {  
  20.         heating = true;  
  21.         System.out.println("-----Heating-----");  
  22.         reportHeating();  
  23.     }  
  24.   
  25.     @UiThread  
  26.     void reportHeating(){  
  27.         Toast.makeText(context,"Electric heater heating.....",Toast.LENGTH_LONG).show();  
  28.     }  
  29.   
  30.     @Override  
  31.     public void off() {  
  32.         heating = false;  
  33.     }  
  34.   
  35.     @Override  
  36.     public boolean isHot() {  
  37.         return heating;  
  38.     }  
  39. }  

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

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

Pump接口实现:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2. import javax.inject.Inject;  
  3.   
  4. /** 
  5.  * Created by zjb on 14-1-22. 
  6.  */  
  7. class Thermosiphon implements Pump {  
  8.     private final Heater heater;  
  9.     boolean pumped = false;  
  10.   
  11.     @Inject  
  12.     Thermosiphon(Heater heater) {  
  13.         this.heater = heater;  
  14.     }  
  15.   
  16.     @Override  
  17.     public void pump() {  
  18.         if (heater.isHot()) {  
  19.             System.out.println("-----Pumping-----");  
  20.             pumped = true;  
  21.             try {  
  22.                 Thread.sleep(1000);  
  23.             } catch (InterruptedException e) {  
  24.                 e.printStackTrace();  
  25.             }  
  26.         }  
  27.     }  
  28.     @Override  
  29.     public boolean isPumped() {  
  30.         return pumped;  
  31.     }  
  32. }  


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2. import javax.inject.Inject;  
  3.   
  4. /** 
  5.  * Created by zjb on 14-1-22. 
  6.  */  
  7. class PeopleDrink implements Drink {  
  8.     private Pump pump;  
  9.      @Inject  
  10.      PeopleDrink(Pump pump) {  
  11.         this.pump = pump;  
  12.     }  
  13.     @Override  
  14.     public void drink(){  
  15.         if(pump.isPumped()){  
  16.             System.out.println("-----Drinking-----");  
  17.         }  
  18.         try {  
  19.             Thread.sleep(1000);  
  20.         } catch (InterruptedException e) {  
  21.             e.printStackTrace();  
  22.         }  
  23.     }  
  24. }  
  三个接口已经实现完毕,对比三个实现类,有没有发现什么共同点. 是的,你会发现,三个类中都有使用@Inject来注解

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

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

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

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2. import javax.inject.Inject;  
  3. import dagger.Lazy;  
  4. /** 
  5.  * Created by zjb on 14-1-22. 
  6.  */  
  7.   
  8. class CoffeeMaker {  
  9.     @Inject  
  10.     Lazy<Heater> heater;  
  11.     @Inject  
  12.     Pump pump;  
  13.     @Inject  
  14.     Drink drink;  
  15.   
  16.     public void brew() {  
  17.         heater.get().on();  
  18.         pump.pump();  
  19.         System.out.println("-----Pumped-----");  
  20.         heater.get().off();  
  21.         drink.drink();  
  22.     }  
  23. }  
将Heater、Pump及Drink注入到类CoffeeMaker中,就可以直接使用并调用其方法。值得注意的是,在注解的时候Dagger

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

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

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2.   
  3. import android.content.Context;  
  4. import javax.inject.Singleton;  
  5. import dagger.Module;  
  6. import dagger.Provides;  
  7.   
  8. /** 
  9.  * Created by zjb on 14-1-22. 
  10.  */  
  11. @Module(injects={CoffeeActivity_.class},library = true,complete = false)  
  12. /*@Module(injects = {CoffeeActivity_.class},includes = {PumpModule.class,DrinkModule.class},library = true,complete = false)*/  
  13. class DripCoffeeModule {  
  14.     private final Context context;  
  15.   
  16.     public DripCoffeeModule(Context context) {  
  17.         this.context = context.getApplicationContext();  
  18.     }  
  19.   
  20.     @Provides  
  21.     @Singleton  
  22.     Context appliactionContext() {  
  23.         return context;  
  24.     }  
  25.   
  26.     @Provides  
  27.     @Singleton  
  28.     Heater provideHeater(){  
  29.         return ElectricHeater_.getInstance_(appliactionContext());  
  30.     }  
  31.   
  32.     @Provides  
  33.     @Singleton  
  34.     Drink provideDrink(PeopleDrink drink){  
  35.         return drink;  
  36.     }  
  37.   
  38.     @Provides  
  39.     @Singleton  
  40.     Pump providePump(Thermosiphon pump){  
  41.         return pump;  
  42.     }  
  43. }  

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

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

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

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

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2. import dagger.Module;  
  3.   
  4. /** 
  5.  * Created by zjb on 14-1-22. 
  6.  */  
  7. @Module(library = true,complete = false)  
  8. public class DrinkModule {  
  9.     @Provides  
  10.     @Singleton  
  11.     Drink provideDrink(PeopleDrink drink){  
  12.         return drink;  
  13.     }  
  14. }  
(@Module后的library和complete是什么意思这里先不说)

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

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2. import android.app.Application;  
  3.   
  4. import org.androidannotations.annotations.EApplication;  
  5.   
  6. import dagger.ObjectGraph;  
  7.   
  8. /** 
  9.  * Created by zjb on 14-1-22. 
  10.  */  
  11.   
  12. @EApplication  
  13. public class CoffeeApplication extends Application {  
  14.     private ObjectGraph objectGraph;  
  15.   
  16.     @Override  
  17.     public void onCreate() {  
  18.         super.onCreate();  
  19.         objectGraph = ObjectGraph.create(new DripCoffeeModule(this));  
  20.     }  
  21.   
  22.     public ObjectGraph getObjectGraph() {  
  23.         return objectGraph;  
  24.     }  
  25.   
  26. }  
上边提到,Dagger是通过什么管理或者组织依赖关系的呢,就是通过ObjectGraph(对象图表)。

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

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.example.app.dagger;  
  2.   
  3. import android.app.Activity;  
  4. import android.widget.Toast;  
  5. import com.example.app.R;  
  6. import org.androidannotations.annotations.AfterInject;  
  7. import org.androidannotations.annotations.App;  
  8. import org.androidannotations.annotations.Background;  
  9. import org.androidannotations.annotations.Click;  
  10. import org.androidannotations.annotations.EActivity;  
  11. import org.androidannotations.annotations.UiThread;  
  12. import javax.inject.Inject;  
  13. import dagger.ObjectGraph;  
  14.   
  15. /** 
  16.  * Created by zjb on 14-1-22. 
  17.  */  
  18.   
  19. @EActivity(R.layout.coffee)  
  20. public class CoffeeActivity extends Activity {  
  21.     @App  
  22.     CoffeeApplication coffeeApplication;  
  23.     @Inject  
  24.     CoffeeMaker maker;  
  25.   
  26.     @AfterInject  
  27.     void daggerInject(){  
  28.         ObjectGraph objectGraph = coffeeApplication.getObjectGraph();  
  29.         objectGraph.inject(this);  
  30.     }  
  31.     @Click(R.id.coffeeClick)  
  32.     @Background  
  33.     void coffeeClicked(){  
  34.         maker.brew();  
  35.         coffeeBrew();  
  36.     }  
  37.     @UiThread  
  38.     void coffeeBrew(){  
  39.         Toast.makeText(this,"Coffee has been pumped...",Toast.LENGTH_LONG).show();  
  40.     }  
  41. }  

程序运行的结果:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. com.example.app I/System.out﹕ -----Heating-----  
  2. com.example.app I/System.out﹕ -----Pumping-----  
  3. com.example.app I/System.out﹕ -----Pumped-----  
  4. com.example.app I/System.out﹕ -----Drinking-----  

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

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


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

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

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

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

附:

Demo 下载

Jake Warhton的Dagger ppt  下载资源

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值