Dagger2运行原理分析以及MVP案例

Dagger2:

用途:假设有类A,类B,A类中包含一个B的实例

,那么生成这种关系有几种方法,方法一:a.setB(B b);方法二:在A的构造函数中传入B,public A(B b){}.不管用什么方法,都需要new B().如果哪一天业务需求有变,就需要改动所有new B()的地方,耦合性很强。如果使用dagger依赖注入后,后面去如果需要修改B对象,改动的地方会很少,降低了耦合性,减少了new B()代码的编写。

框架流程:

属于编译期间生效,自动生成相关代码。

先搬一个简单的dagger注入的示例代码:首先添加相关jar包以及apt 插件依赖。

类B:

public class QueryModel {

        

         @Inject //这个表示QueryModel可以被依赖注入,该构造方法会被注入。

         publicQueryModel() {

         }

         publicvoid queryNum(String number,IQueryListener listener){

                 

                  for(int i = 0; i < 10000; i++) {

                  }

                  listener.querySuccess();

                 

         }

}

类A:

public class QueryPresenter implementsIQueryListener {

        

         privateIQueryView view;

         @Inject这里表示这个示例可以被依赖注入。

          QueryModel model;

        

         @Inject

         publicQueryPresenter(IQueryView view) {

                  this.view= view;

                  DaggerQueryProcessorComponent.builder().build().inject(this);//开始进行注入

         }

        

         publicvoid startQuery(String number) {

                  model.queryNum(number,this);

         }

        

         @Override

         publicvoid querySuccess() {

                  view.showSuccessMsg();

         }

        

         @Override

         publicvoid queryFail() {

                  view.showErrorMsg();

         }

}

类C:

@Component //哪个对象需要依赖注入,那么就需要有对应的Component组件。需要写成interface或者是abstractclass. 以类A类B的关系来比喻,就是类A中含有类B的示例,并且B的示例是通过依赖注入拿到,那么A就需要这个Component.框架自动生成的component是容器实例是:Dagger+component名字,示例中的就是DaggerQueryProcessorComponent

@Component

public interface QueryProcessorComponent {

         voidinject(QueryPresenter presenter);//注意这个注入参数,声明的是什么类型,就必须在什么类型中注入,不能在这里声明一个父类,而跑到子类中去注入。

}

最简单的dagger的框架使用就是如上,红色的注释已经做了简单说明。当类B需要被注入时,就在B的构造方法上加一个@Inject注解,在使用的地方,在声明的变量上面加一个@Inject参数。这样导致问题是,只能注入我们自己写的类,如果是android.jar的类,或者第三方jar中的类,我们就无法进行注入。那么如何解决呢?就需要用到@Module以及@Provides注解了。

@Module module的用途是提供dagger注解需要的实例对象(无法通过在构造方法上加@inject获得实例的),@module用于提供实例的类的注解,@provides用于注解提供类实例的方法。貌似注入框架是优先查找module来获得需要被注入的示例,没有在module中找到的话,再去找构造函数。

还有一点,在最简单的dagger框架使用示例中,构造函数QueryModel()是不带参数的,那么如果带了参数呢?参数怎么传递进去,也是通过@module和@provides来提供(当dagger框架注入对象的时候,如果使用@module注解的类的构造函数需要参数,那么需要通过.appModule(newModule(形参)来传入))。

@Module

public class ActivityModule {

        

         privateIQueryView view;

         privateContext context;

         publicActivityModule(IQueryView view, Context context) {

                  this.view= view;

                  this.context= context;

         }

        

         @Provides

         IQueryViewprovideIQueryView(){

                  returnview;

         }

        

         @Provides

         SharedPreferencesproviderGlobalSharedPreference(){

                  returnPreferenceManager.getDefaultSharedPreferences(context);

         }

}

@Component(modules = ActivityModule.class)

public interface ActivityComponent {

        

         voidinject(DaggerActivity activity);

}

//这里的modules也可以有多个,总之voidinject(DaggerActivity activity)中的参数activity依赖注入的对象需要哪些通过module拿到的参数,都需要在modudles属性中列出来

使用依赖注入的activity:

public class DaggerActivity extendsAppCompatActivity implements IQueryView {

        

         @Inject

         QueryPresentermPresenter;//因为presenter 的构造函数需要参数,所以需要对daggerActivity的注入容器提供一个方法,用来提供生成presenter所需要的参数。

        

         @Override

         protectedvoid onCreate(Bundle savedInstanceState) {

                  super.onCreate(savedInstanceState);

                  setContentView(R.layout.activity_dagger);

在这里进行注入,这个类是自动生成的

                  DaggerNewActivityComponent.builder().activityModule(newActivityModule(this,this)).build().inject(this);//

                 

//              mPresenter= new QueryPresenter(this);

//              DaggerActivityComponent.builder().build().inject(this);第一个

                  //对比这个2个注入方式,发现如果需要参数的话,那么就需要在builder()和build()之间插入对应的module(就是提供参数的module),注意:这个方法activityModule()是框架自动生成的。

         }

        

         @Override

         publicvoid showSuccessMsg() {

                  Toast.makeText(DaggerActivity.this,"成功", Toast.LENGTH_SHORT).show();

         }

        

         @Override

         publicvoid showErrorMsg() {

                  Toast.makeText(DaggerActivity.this,"失败", Toast.LENGTH_SHORT).show();

                 

         }

}

***************************************************

Dagger2 编译后代码注入流程分析:这里不是原理,这是根据dagger框架自动生成的代码做流程分析。

分析起点是:在类A中写了一个类B的实例b,分析这个b是如何生成的。就根据注入代码

 DaggerAppComponent.builder().

                appModule(newAppModule(getApplicationContext())).

                httpModule(newHttpModule(getApplicationContext())).build().inject(this);根据这个代码的执行过程就可以了。

首先看其内部类Builder:

public static final class Builder {

   private HttpModule httpModule; // 这里对应的是你添加的每个module

   private AppModule appModule;

   private Builder() {}

    publicAppComponent build() {//调用build()方法时,会检测是否有set每一个module,没有的话就抛异常

      if(httpModule == null) {

       throw new IllegalStateException(HttpModule.class.getCanonicalName() +" must be set");

      }

      if(appModule == null) {

       throw new IllegalStateException(AppModule.class.getCanonicalName() +" must be set");

      }

     return new DaggerAppComponent(this);//这里也需要分析

    }

    publicBuilder appModule(AppModule appModule) {

     this.appModule = Preconditions.checkNotNull(appModule);

     return this;

    }

    publicBuilder httpModule(HttpModule httpModule) {

     this.httpModule = Preconditions.checkNotNull(httpModule);

     return this;

    }

  }

DaggerAppComponent自己的构造方法:

private DaggerAppComponent(Builder builder) {

    assertbuilder != null;

    initialize(builder);

  }

initialize(builder);

 @SuppressWarnings("unchecked")

  privatevoid initialize(final Builder builder) {

*包括的都是对象实例提供者

 **************************************************

   this.provideTestInstanceProvider =

        HttpModule_ProvideTestInstanceFactory.create(builder.httpModule);这里也是关键方法。对应的是我们的加的@provides注解

this.provideSharedPrefProvider= AppModule_ProvideSharedPrefFactory.create(builder.appModule);

*******************************************

下面的是injector是真正的注入执行者,在create()将所有需要的被加入到容器中的对象通过参数传递进去。

   this.baseMvpActivityMembersInjector =

       BaseMvpActivity_MembersInjector.create(

           User_Factory.create(), provideTestInstanceProvider,provideSharedPrefProvider);

  }

经过分析可以发现,针对于每个module中的每一个provider方法,都会生成一个对应的factory方法。以其中一个为例:

public final classAppModule_ProvideSharedPrefFactory implements Factory<SharedPreferences>{

  privatefinal AppModule module;

  publicAppModule_ProvideSharedPrefFactory(AppModule module) {

    assertmodule != null;

   this.module = module;

  }

 @Override

  publicSharedPreferences get() {//这里的get()调用的是传进来的module的我们注解了@provide的方法,这样就可以通过这个工厂对象的get()获得我们定义的注解对象。

    returnPreconditions.checkNotNull(

       module.provideSharedPref(), "Cannot return null from anon-@Nullable @Provides method");

  }

  publicstatic Factory<SharedPreferences> create(AppModule module) {

    returnnew AppModule_ProvideSharedPrefFactory(module);

  }

}

接下来就是关键了,调用链最后的inject(this):

 @Override

 public void inject(BaseMvpActivity mvpActivity) {

   baseMvpActivityMembersInjector.injectMembers(mvpActivity);

  }

public BaseMvpActivity_MembersInjector(

     Provider<User> userProvider,

     Provider<TestInstance> testInstanceProvider,

      Provider<SharedPreferences>sharedPreferencesProvider) {

    assertuserProvider != null;

   this.userProvider = userProvider;

    asserttestInstanceProvider != null;

   this.testInstanceProvider = testInstanceProvider;

    assertsharedPreferencesProvider != null;

   this.sharedPreferencesProvider = sharedPreferencesProvider;

  }

  publicstatic MembersInjector<BaseMvpActivity> create(

     Provider<User> userProvider,

     Provider<TestInstance> testInstanceProvider,

     Provider<SharedPreferences> sharedPreferencesProvider) {

    returnnew BaseMvpActivity_MembersInjector(

       userProvider, testInstanceProvider, sharedPreferencesProvider);

  }

  @Override

  public void injectMembers(BaseMvpActivityinstance) {

    if (instance == null) {

      throw newNullPointerException("Cannot inject members into a null reference");

}

在这里将BaseMvpActivity中的被@inject标注的依赖注入的对象进行赋值。这样就完成了整个依赖注入过程。

    instance.user = userProvider.get();

    instance.testInstance =testInstanceProvider.get();

    instance.sharedPreferences =sharedPreferencesProvider.get();

  }

  publicstatic void injectUser(BaseMvpActivity instance, Provider<User>userProvider) {

   instance.user = userProvider.get();

  }

  publicstatic void injectTestInstance(

     BaseMvpActivity instance, Provider<TestInstance>testInstanceProvider) {

   instance.testInstance = testInstanceProvider.get();

  }

  publicstatic void injectSharedPreferences(

     BaseMvpActivity instance, Provider<SharedPreferences>sharedPreferencesProvider) {

   instance.sharedPreferences = sharedPreferencesProvider.get();

  }

}

用uml表示如下:

再来讲讲@Scope注解的使用:

Scope字面理解就是范围的意思,在java中可以理解为作用域。

在android中,有些对象是全局application的,有些对象可能会有多个activity共享,这个时候就需要用到scope注解了。注意:如果对于自己写的对象,使用单例的话,就需要在module中提供provide方法,不能通过inject构造方法的形式来提供。

使用步骤如下:

1、建立一个scope,命名随意,形式固定。


@Scope

@Retention(RetentionPolicy.RUNTIME)

public @interface ActivityScope {

}

2、在需要使用scope的module中的provide方法上加上scope注解。

@Module

public class AppModule {

private Context context;

    publicAppModule(Context context) {

       this.context = context;

}

    @Provides

    @ActivityScope//加上scope注解

    User providersssssssUser(){

        return new User();

    }

}
3、在声明的注解容器上加上scope。

@ActivityScope

@Component(modules = {AppModule.class,HttpModule.class})//凡是module使用到了scope,那么容器中必须写上scope,否则编译不过。

public interface AppComponent {

    //

    voidinject(BaseMvpActivity mvpActivity);

    voidinject(BaseMvp2Activity second_activity);

}

4、在application中要生成容器(需要保证只能实例化容器一次,否则不可能是单例)

public class DaggerApplication extendsApplication {

   AppComponent appComponent;

   @Override

    publicvoid onCreate() {

       super.onCreate();

       getAppComponent();

    }

    publicAppComponent getAppComponent(){

        if(appComponent == null) {

           appComponent = DaggerAppComponent.builder().

                    appModule(newAppModule(getApplicationContext())).

                    httpModule(newHttpModule(getApplicationContext())).build();

        }

       return appComponent;

    }

}

5、在需要注入的activity中进行注入。

((DaggerApplication)getApplication()).getAppComponent().inject(this);

这样下来,就能保证2个activity拿到是同一个user对象了。

至于为什么这样加上scope就能实现单例,可以通过dagger框架生成的代码来分析。就以user对象来分析。

在前面的代码中有提高,自动生成的注解容器对象DaggerAppComponent针对module中的每一个provide方法都会生成Provider<T>的泛型对象,然后通过provider.get()方法拿到对应的实例。

当我们不加scope注解时,生成usrprovider的代码如下:

userProvider = AppModule_ProvidersssssssUserFactory.create(builder.appModule);

当需要user实例时,就会调用appmodule.providerUser(),实际就会生成一个user实例,如果多次调用inject(),肯定会生成多个user对象,自然不是单例的。

那么如果加了scope操作后呢,框架生成的代码如下。

Userprovider =DoubleCheck.provider(AppModule_ProvidersssssssUserFactory.create(builder.appModule));

会发现对usrprovider进行了一次doublecheck的包装。那么当调用userprovider.get()实际调用的是doubleCheck.get(),接下来看看doubleCheck.get()的具体实现。

private static final Object UNINITIALIZED = newObject();

  privatevolatile Object instance = UNINITIALIZED;

@SuppressWarnings("unchecked") // castonly happens when result comes from the provider

 @Override

  public Tget() {

    Object result = instance;

    if (result == UNINITIALIZED) {通过这里判断result是否有被初始化过

      synchronized (this) {//代码同步,这里还保证了线程安全

       result = instance;

        if(result == UNINITIALIZED) {

         instance = result = provider.get();

         /* Null out the reference to the provider. We are never going to need itagain, so we

          * can make it eligible for GC. */

         provider = null;

        }

      }

    }

    return(T) result;

  }

所以,当我们在不同的地方注入(即获取user对象时),如果该对象已经生成了,就会直接返回,保证了单例。

还有一些不常用的注解:

@dependencies @Named

@dependencies:用于组件(component)间的依赖。

用途:假设我有一个application级别的component(里面注入的对象肯定有单一实例的sharedPreference\context\登陆的用户等等),那么我activity级别的component肯定会用到这些实例对象,这个时候activity component就需要依赖application component.

写法:

@Component(dependencies={Appcomponent.class},modules={})

Public interfaceActivityComponent{

}

规则:1、假设activitycomponent希望使用application component中的sharedPreference,那么就必须在application component 中提供一个暴露sharedpreference的方法。

@ActivityScope

@Component(dependencies= {},modules = {AppModule.class, HttpModule.class})

public interfaceAppComponent {

//    void inject(BaseMvpActivity mvpActivity);

    void inject(BaseMvp2Activitysecond_activity);

    SharedPreferences SharedPreferences();

}

2、依赖与被依赖的组件的scope必须不同。

@named:用于区别多个同一类型的实例。

用途:假设我要提供2种sharedpreference,一种是默认的,一种是保存cache的。我们就可以在AppModule中写2个方法,分别提供2种不同的sharedpreference。

AppModule:

@Named("default")

   @Provides

   SharedPreferences provideSharedPref(){

       return PreferenceManager.getDefaultSharedPreferences(context);

    }

   @Named("cached")

   @Provides

   SharedPreferences provideCachedSharedPref(){

       return context.getSharedPreferences("cached",Context.MODE_PRIVATE);

    }

在被注入的地方的实例名上加上@named注解,就可以获取指定的sharedpreference了。

MainActivity:

 @Named("cached")

   @Inject

   protected SharedPreferences sharedPreferences;

   @Named("default")

   @Inject

   protected SharedPreferences sharedPreferencesDefault;

这里需要注意的一点是:如果有依赖关系,activitycomponent用到了default和cached两种sharedpreference,因为application component需要暴露对象的方法,那么现在就需要提供两个针对@Named的方法。

ApplicationComponent:

@Named("cached")

   SharedPreferences SharedPreferences();

   @Named("default")

   SharedPreferences SharedPreferences2();

基本dagger2的用法就分析完毕了。


猜你喜欢

转载自blog.csdn.net/HelloMagina/article/details/79533841
今日推荐