注解Dagger21-Android开发知识

深入浅出Dagger2 : 从入门到爱不释手

2018-05-06  本文已影响6311人  your_genius

Dagger2是什么?

Dagger2是Dagger的升级版,是一个依赖注入框架,第一代由大名鼎鼎的Square公司共享出来,第二代则是由谷歌接手后推出的,现在由Google接手维护.

Github地址

那么,什么是依赖注入?

依赖注入是面向对象编程的一种设计模式,其目的是为了降低程序耦合,这个耦合就是类之间的依赖引起的.

举个栗子:

    public class ClassA{
        private ClassB b
        public ClassA(ClassB b){
        this.b = b    }
    }

这里ClassA的构造函数里传了一个参数ClassB,随着后续业务增加也许又需要传入ClassC,ClassD.试想一下如果一个工程中有5个文件使用了ClassA那是不是要改5个文件?

这既不符合开闭原则, 也太不软工了.这个时候大杀器Dagger2就该出场了.

  public class ClassA{
     @inject 
      private ClassB b 
      public ClassA(){
       }
    }

通过注解的方式将ClassB b注入到ClassA中, 可以灵活配置ClassA的属性而不影响其他文件对ClassA的使用.

如何使用Dagger2

下面就跟着我的节奏来在实际项目中体验一下Dagger2.我手头有一个MVP模式的地图导航的Demo, 我们就来使用Dagger2改造它.

1.导入

compile"com.google.dagger:dagger:2.14.1"
annotationProcessor"com.google.dagger:dagger-compiler:2.14.1"

咦?一般的第三方库像Glide,okhttp不都是一行代码引入吗?这里怎么多了一个annotationProcessor?估计用过其他注解框架比如Butterknife,EventBus的同学已经了然了,小白也不要急,此处且留个悬念.

2.定义一个注解ActivityScope, 创建一个接口CommonComponent, 创建一个类CommonModule

  @Scope
  @Retention(RetentionPolicy.RUNTIME)
   public @interface ActivityScope {
   }
  @ActivityScope
  @Component (modules = CommonModule.class)
   public interface CommonComponent {
   void inject(GdmapActivity activity);  //GdmapActivity是导航Demo的一个Activity
   }
@Module
 public class CommonModule{
 }

@Scope和@Retention是元注解, 大家应该是了解的, @Component@Module是Dagger2定义的注解. 那这三个文件分别是干啥用的呢?先带着这个问题, 我们一边用一边去理解.

3.使用我们定义的Module和Component开始改造导航Demo

Demo中之前有个Presenter长这样(prenter中具体的业务逻辑先忽略, 后面会附上完整Demo的git地址)

public class Gpresenter { 
  private ILocateView view;
  private Application application;
  private RxErrorHandler rxErrorHandler;
   /**定位类对象*/
  private AMapLocationClient mLocationClient;
  /**逆地理编码类对象*/
  private GeocodeSearch mGeocodeSearch;
  /**地理围栏类对象*/
  private GeoFenceClient fenceClient;
  public Gpresenter(Application application,
                         ILocateView view,
                         RxErrorHandler rxErrorHandler,
                         AMapLocationClient mLocationClient, 
                         GeocodeSearch mGeocodeSearch,
                         GeoFenceClient fenceClient) {   
           this.view = view; 
           this.application = application; 
           this.rxErrorHandler = rxErrorHandler; 
           this.mLocationClient = mLocationClient; 
           this.mGeocodeSearch = mGeocodeSearch; 
           this.fenceClient = fenceClient; 
     }

改造前在Activity中初始化这个Gpresenter:

 public class GdmpActivity extends GdBaseActivity implements ILocateView {
      protected Gdpresenter gdpresenter; 
      @Override 
       protected void onCreate(@Nullable Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             initPresnter();
       }

      private void initPresnter(){ 
             RxErrorHandler handler =  RxErrorHandler.builder().with(getApplication()); 
             responseErrorListener(ResponseErrorListener.EMPTY).build();
             AMapLocationClient client =new AMapLocationClient(this);
             GeocodeSearch codeSearch =new GeocodeSearch(this); 
             GeoFenceClient fenceClient =new GeoFenceClient(this); 
              gdpresenter =new
              Gdpresenter(getApplication(),this,handler,client,codeSearch,fenceClient); 
         }
    }

现在我们把Gpresenter初始化的事交给Dagger2去做.优雅的省略GdmpActivity中初始化Gdpresenter的过程.
先使用我们刚才定义的CommonModule :

@Module
 public class CommonModule{
     private ILocateView view; 
     public CommonModule(ILocateView view){ 
         this.view = view;
     } 

     @ActivityScope
     @Provides
     public ILocateViewprovideIView(){ 
         return this.view; 
     }

     @ActivityScope
     @Provides 
     public Application provideApplication(){ 
       return view.getActivity().getApplication();
     }
    
     @ActivityScope
     @Provides
     public RxPermissions provideRxPermission(){
         return new RxPermissions(view.getActivity()); 
     }
 
     @ActivityScope
     @Provides
     public AMapLocationClient provideAMapLocationClient(){  
         return new AMapLocationClient(view.getActivity()); 
     }
 
     @ActivityScope 
     @Provides
     public GeocodeSearch provideGeocodeSearch(){ 
         return new GeocodeSearch(view.getActivity());
 
     }

     @ActivityScope 
     @Provides 
     public GeoFenceClientgetGeoFenceClient(){
         return new GeoFenceClient(view.getActivity().getApplicationContext()); 
     }
 
     @ActivityScope 
     @Provides 
     public RxErrorHandlerprovideRxErrorHandler(Application application ){
          return  RxErrorHandler.builder().with(application).   
                            responseErrorListener(ResponseErrorListener.EMPTY).build();
     }

解释一下, 我们自定义的Annotation @ActivityScope指定作用域, ActivityScope 的元注解@Retention(RetentionPolicy.RUNTIME)指定了它是运行时注解,就是说注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在.
@Provides是Dagger2定义的Annotation(待深挖)
同时给Gpresnter加上注释 @Inject

 @Inject
 public Gpresenter(Application application, ILocateView view, RxErrorHandler rxErrorHandler,                                          AMapLocationClient mLocationClient,GeocodeSearch mGeocodeSearch, 
                              GeoFenceClient fenceClient)

现在build一下,看看项目的build-->generate-->source-->apt目录下面都有什么:

image

生成了很多CommonModule开头的.class文件,还有DaggerCommonComponent,这都是哪来的?
在build的过程中,APT(就是dagger-compiler)扫描到注解(@Component@Module)生成的.这个过程用下面这张图表示:


image.png

该最后一步了: 把Gpresenter初始化的事交给Dagger2去做.在GdmapActivity中给Gpresenter加上@Inject标签, 同时删掉Gpresenter初始化过程

 public class GdmapActivity implements ILocateView {
       @Inject 
       protected Gdpresenter gdpresenter; 
       @Override
       protected void onCreate(@Nullable Bundle savedInstanceState) { 
           super.onCreate(savedInstanceState); 
           DaggerCommonComponent.builder().
            commonModule(new CommonModule(this)).
            build().inject(this);  
        }
   }

是不是清爽了很多?
那么,Dagger2是如何工作的?
生成的*.class文件里面主要做了什么?
这些文件时如何生成的呢?
且等后续

Demo github地址

参考博客:

Dagger2:

https://www.jianshu.com/p/22c397354997

https://www.jianshu.com/p/39d1df6c877d

APT:

https://www.jianshu.com/p/1910762593be

https://blog.csdn.net/Ru_Zhan/article/details/78232851?locationNum=8&fps=1

上一篇下一篇

猜你喜欢

热点阅读