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
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
returnnew AppModule_ProvideSharedPrefFactory(module);
}
}
接下来就是关键了,调用链最后的inject(this):
@Override
public void inject(BaseMvpActivity mvpActivity) {
baseMvpActivityMembersInjector.injectMembers(mvpActivity);
}
public BaseMvpActivity_MembersInjector(
Provider
Provider
Provider
assertuserProvider != null;
this.userProvider = userProvider;
asserttestInstanceProvider != null;
this.testInstanceProvider = testInstanceProvider;
assertsharedPreferencesProvider != null;
this.sharedPreferencesProvider = sharedPreferencesProvider;
}
publicstatic MembersInjector
Provider
Provider
Provider
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
instance.user = userProvider.get();
}
publicstatic void injectTestInstance(
BaseMvpActivity instance, Provider
instance.testInstance = testInstanceProvider.get();
}
publicstatic void injectSharedPreferences(
BaseMvpActivity instance, Provider
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
当我们不加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的用法就分析完毕了。