您的位置:首页 > 其它

Dagger入门二

2017-03-08 18:25 246 查看


Dagger2使用攻略

Dagger 2 是 Square 的 Dagger 分支,是一种依赖注入框架。目前由 Google 接手进行开发,Dagger2是使用代码自动生成和手写代码来实现依赖注入。据说在 Dagger 的基础上效率又提升了13%,并且同样功能强大。


1.Gradle配置

(1)需要配置apt 插件:(在project根目录
build.gradle
文件中添加如下代码)
dependencies {
...
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}


(2)添加依赖:(在module
build.gradle
文件中添加如下代码)
apply plugin: 'com.neenbedankt.android-apt'// 注释处理

dependencies {
...
compile 'com.google.dagger:dagger:2.0.2'
apt 'com.google.dagger:dagger-compiler:2.0.2'
compile 'org.glassfish:javax.annotation:10.0-b28' // Java标注
}


● 当前最新版本是2.0.2

● 添加2、3条依赖的原因参考:Dagger2入坑指南

● 如果在项目中同时用了
Butterknife
,在Build时会报注释冲突。 



解决方法:(在module
build.gradle
文件中添加如下代码)
packagingOptions { exclude 'META-INF/services/javax.annotation.processing.Processor' }


(3)最后点击
Build-->Make Project
就可以开始使用
Dagger2
了。


2.Dagger2 常用注解

写了一个简单的Demo,下面根据Demo进行介绍。Dagger2要理解必须看Dagger 2自动生成的代码,Build后代码在
项目-->app-->build-->generated-->source-->apt-->debug
目录下。


1.Inject

@Inject
:在需要依赖的地方使用这个注解,告诉Dagger这个类或者字段需要依赖注入,这样Dagger会构造一个这个类实例来满足依赖。

1.构造器注入:首先举一个简单的例子,无参构造方法。
public class Person {
private String name;
private int age;

@Inject
public Person() {
}

public String getName() {
return "Jack";
}

public int getAge() {
return 15;
}

}


这个的局限性是我们不能给这个类中的多个构造器作
@Inject
注解。

2.注解成员变量:

接着上面我们要使用这个实例化类。
public class MainActivity extends AppCompatActivity {

@Inject
Person mPerson;

StorageComponent mStorageComponent;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mStorageComponent = ((MyApplication)this.getApplication()).getStorageComponent();
mStorageComponent.inject(this);//注入MainActivity

Toast.makeText(this,mPerson.getName() + "----" +mPerson.getAge(),Toast.LENGTH_SHORT).show();
}
}


这里我们可以查看生成的代码:
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final MembersInjector<AppCompatActivity> supertypeInjector;
private final Provider<Person> mPersonProvider;

public MainActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<Person> mPersonProvider) {

assert supertypeInjector != null;
this.supertypeInjector = supertypeInjector;
assert mPersonProvider != null;
this.mPersonProvider = mPersonProvider;
}

@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.mPerson = mPersonProvider.get();//这里mPersonProvider替我们实例化了Person
}

public static MembersInjector<MainActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<Person> mPersonProvider) {
return new MainActivity_MembersInjector(supertypeInjector, mPersonProvider);
}
}


同时我们也可以了解到
@Inject Person mPerson;
 为什么不能使用
private
 。上面代码中的
injectMembers
 方法调用后面会说到。

3.方法注入
public class LoginActivityPresenter {

private LoginActivity loginActivity;

@Inject //构造方法注入
public LoginActivityPresenter(LoginActivity loginActivity) {
this.loginActivity = loginActivity;
}

@Inject //方法注入
public void enableWatches(Watches watches) {
watches.register(this);
}
}


如当我们希望传入类的当前实例(this引用)到被注入的依赖中。方法注入会在构造器调用后马上被调用,所以这表示我们可以传入完全被构造的this。


2.Module

@Module
:用来修饰类,表示此类的方法是用来提供依赖的,它告诉Dagger在哪里可以找到依赖。
@Module
public class StorageModule {

private final MyApplication application;

public StorageModule(MyApplication application) {
this.application = application;
}

@Provides
@Singleton
SharedPreferences provideSharedPreferences(){
return PreferenceManager.getDefaultSharedPreferences(application);
}

}


@Provides
下面说到,
@Singleton
 单例,使用
@Singleton
注解之后,对象只会被初始化一次,之后的每次都会被直接注入相同的对象。
@Singleton
就是一个内置的作用域。


3.Provides

@Provides
:在
@Module
 中使用,我们定义的方法用这个注解,用于告诉
Dagger 我们需要构造实例并提供依赖。

为什么要使用
@Provides
,因为默认情况下,Dagger满足依赖关系是通过调用构造方法得到的实例,比如上面的Person类使用。但是有时因为
@Inject
 的局限性,我们不能使用
@Inject
。比如构造方法有多个、三方库中的类我们不知道他是怎么实现的等等。例如下面代码中的
SharedPreferences
,我们使用
@Provides
 返回一个创建好的实例,这样做也显得灵活不是吗?
@Provides
@Singleton
SharedPreferences provideSharedPreferences(){
return PreferenceManager.getDefaultSharedPreferences(application);
}


注意:

● 按照习惯 
@Providers
方法都会用provide作为前缀,
@Module
类都用Module作为后缀。

● 如果
@Provides
方法有参数,这个参数也要保证能够被Dagger得到(例如通过其他的
@Provides
方法或者@Inject注解的构造方法。)


4.Component

@Component
: 是
@Inject
@Module
的桥梁,需要列出所有的@Modules以组成该组件。
@Singleton
@Component(modules = {
StorageModule.class ,
ScheduleModule.class
})
public interface StorageComponent {

Storage execute();
void inject(MainActivity mMainActivity);
}


Dagger会按照上面接口生成一个实现类,生成类以Dagger为前缀,提供builder()来生成实例。调用方法:(因为是单例,所以这里放到了MyApplication)
public class MyApplication extends Application {

private StorageComponent component;

@Override
public void onCreate() {
super.onCreate();

component = DaggerStorageComponent
.builder()//调用构建类
.storageModule(new StorageModule(this)) //传入Module
.build();//生成实例

}

public StorageComponent getStorageComponent() {
return component;
}

}


MainActivity代码:
public class MainActivity extends AppCompatActivity {

@Bind(R.id.button1)
Button mButton1;

@Bind(R.id.button2)
Button mButton2;

@Inject
SharedPreferences mPreferences;//全局的SharedPreferences

@Inject
Person mPerson;

StorageComponent mStorageComponent;
private final String KEY = "Dagger 2";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);

mStorageComponent = ((MyApplication)this.getApplication()).getStorageComponent();
mStorageComponent.inject(this);//注入MainActivity
mStorageComponent.execute().storage();//执行储存操作

}

@OnClick({R.id.button1,R.id.button2})
void onButtonClicked(View v) {
switch (v.getId()) {
case R.id.button1:
Toast.makeText(this,mPreferences.getString(KEY,"---"),Toast.LENGTH_SHORT).show();
//上面是示例获取mPreferences,实际中将SharedPreferences操作都可以封装进Storage中,如下
//Toast.makeText(this,
//mStorageComponent.execute().getStorage(),Toast.LENGTH_SHORT).show();
break;
case R.id.button2:
Toast.makeText(this,

11c22
mPerson.getName() + "----" + mPerson.getAge(),Toast.LENGTH_SHORT).show();
break;
}
}
}


下来把整个流程走一遍:首先进入
MyApplication
 执行
DaggerStorageComponent.builder().storageModule(new
StorageModule(this)).build();
 方法获取实例化
StorageComponent
。那我我们查看
DaggerStorageComponent
 类:
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerStorageComponent implements StorageComponent {
private Provider<SharedPreferences> provideSharedPreferencesProvider;
private Provider<ScheduleImpl> provideScheduleProvider;
private Provider<Storage> storageProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;

private DaggerStorageComponent(Builder builder) {
assert builder != null;
initialize(builder);
}

public static Builder builder() {
return new Builder();
}

private void initialize(final Builder builder) {
this.provideSharedPreferencesProvider = ScopedProvider.create(StorageModule_ProvideSharedPreferencesFactory.create(builder.storageModule));
this.provideScheduleProvider = ScopedProvider.create(ScheduleModule_ProvideScheduleFactory.create(builder.scheduleModule));
this.storageProvider = Storage_Factory.create(provideSharedPreferencesProvider, provideScheduleProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideSharedPreferencesProvider, Person_Factory.create());//实例化到这里结束
}

@Override
public Storage execute() {
return storageProvider.get();
}

@Override
public void inject(MainActivity mMainActivity) {
mainActivityMembersInjector.injectMembers(mMainActivity);
}

public static final class Builder {
private StorageModule storageModule;
private ScheduleModule scheduleModule;

private Builder() {
}

public StorageComponent build() {
if (storageModule == null) {
throw new IllegalStateException("storageModule must be set");
}
if (scheduleModule == null) {
this.scheduleModule = new ScheduleModule();
}
return new DaggerStorageComponent(this);
}

public Builder storageModule(StorageModule storageModule) {
if (storageModule == null) {
throw new NullPointerException("storageModule");
}
this.storageModule = storageModule;
return this;
}

public Builder scheduleModule(ScheduleModule scheduleModule) {
if (scheduleModule == null) {
throw new NullPointerException("scheduleModule");
}
this.scheduleModule = scheduleModule;
return this;
}
}
}


上面代码最后执行到MainActivity_MembersInjector.create(…)查看
MainActivity_MembersInjector
类:
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final MembersInjector<AppCompatActivity> supertypeInjector;
private final Provider<SharedPreferences> mPreferencesProvider;
private final Provider<Person> mPersonProvider;

public MainActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<SharedPreferences> mPreferencesProvider, Provider<Person> mPersonProvider) {
assert supertypeInjector != null;
this.supertypeInjector = supertypeInjector;
assert mPreferencesProvider != null;
this.mPreferencesProvider = mPreferencesProvider;
assert mPersonProvider != null;
this.mPersonProvider = mPersonProvider;
}

@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.mPreferences = mPreferencesProvider.get();//赋值
instance.mPerson = mPersonProvider.get();
}

public static MembersInjector<MainActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<SharedPreferences> mPreferencesProvider, Provider<Person> mPersonProvider) {
return new MainActivity_MembersInjector(supertypeInjector, mPreferencesProvider, mPersonProvider);
}
}


下来进入到了
MainActivity
 ,在通过
((MyApplication)this.getApplication()).getStorageComponent()
 获取到
component
 后执行
mStorageComponent.inject(this);
 方法注入MainActivity,最终回调到上面代码中的
injectMembers
方法中,可以看出
MainActivity
中的成员变量全部初始完成。之后就可以直接使用了。


5.Lazy 类

Lazy类是实现懒加载,调用的时候才创建实例,通过Lazy对象实现,得到对象的实例使用get()方法。例如:
public class Storage {

private SharedPreferences mPreferences;
private Lazy<ScheduleImpl> mScheduleImpl;//Lazy 类
private final String KEY = "Dagger 2";

@Inject
public Storage(SharedPreferences mPreferences ,Lazy<ScheduleImpl> mScheduleImpl) {
this.mPreferences = mPreferences;
this.mScheduleImpl = mScheduleImpl;
}

public void storage() {
mScheduleImpl.get().start();//get()方法
mPreferences.edit().putString(KEY, "Dagger 2 -- Example").commit();
mScheduleImpl.get().end();
}

}


6.Scope

@Scope
:注解作用域,通过自定义注解限定对象的作用范围。它是JSR-330标准的一部分,其实
@Singleton
就是一种
@Scope
。在Dagger
2中,
@Scope
被用于标记自定义的scope注解。简单说它们可以类似单例地标记依赖。被作注解的依赖会变成单例,但是这会与component的生命周期(不是整个应用)关联。

首先创建一个LoginScope:
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginScope {
}


Module:
@Module
public class LoginModule {

@Provides
@LoginScope  //<---这里为单例
Person providePerson() {
Person mPerson = new Person();
mPerson.setAge(23);
mPerson.setName("WeiLu");
return mPerson;
}
@Provides
Login provideLogin() {
Login mLogin = new Login();
mLogin.setPassword("######");
mLogin.setName("小关");
return mLogin;
}
}


Component:
@LoginScope
@Component(modules = {
LoginModule.class
})
public interface LoginComponent {
void inject(MyApplication myApplication);
}


调用:
mLoginComponent = DaggerLoginComponent.builder()
.loginModule(new LoginModule())
.build();
mLoginComponent.inject(this);


这里我们看一下生成代码:
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerLoginComponent implements LoginComponent {
private Provider<Person> providePersonProvider;
private Provider<Login> provideLoginProvider;
private MembersInjector<MyApplication> myApplicationMembersInjector;

private DaggerLoginComponent(Builder builder) {
assert builder != null;
initialize(builder);
}

public static Builder builder() {
return new Builder();
}

public static LoginComponent create() {
return builder().build();
}

private void initialize(final Builder builder) {
this.providePersonProvider = ScopedProvider.create(LoginModule_ProvidePersonFactory.create(builder.loginModule));
this.provideLoginProvider = LoginModule_ProvideLoginFactory.create(builder.loginModule);
this.myApplicationMembersInjector = MyApplication_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), providePersonProvider, provideLoginProvider);
}

@Override
public void inject(MyApplication myApplication) {
myApplicationMembersInjector.injectMembers(myApplication);
}

public static final class Builder {
private LoginModule loginModule;

private Builder() {
}

public LoginComponent build() {
if (loginModule == null) {
this.loginModule = new LoginModule();
}
return new DaggerLoginComponent(this);
}

public Builder loginModule(LoginModule loginModule) {
if (loginModule == null) {
throw new NullPointerException("loginModule");
}
this.loginModule = loginModule;
return this;
}
}
}


initialize
方法:没有加
@LoginScope
 的Login类,那么他的创建是就是利用工厂模式new了一个Login。相反加了
@LoginScope
 的Person类,是利用
ScopedProvider
 储存了起来。源码如下:
public final class ScopedProvider<T> implements Provider<T> {
private static final Object UNINITIALIZED = new Object();
private final Factory<T> factory;
private volatile Object instance;

private ScopedProvider(Factory<T> factory) {
this.instance = UNINITIALIZED;

assert factory != null;

this.factory = factory;
}

public T get() {
Object result = this.instance;
if(result == UNINITIALIZED) {
synchronized(this) {
result = this.instance;
if(result == UNINITIALIZED) {
this.instance = result = this.factory.get();
}
}
}

return result;
}

public static <T> Provider<T> create(Factory<T> factory) {
if(factory == null) {
throw new NullPointerException();
} else {
return new ScopedProvider(factory);
}
}
}


7.Qualifier

@Qualifier
:限定符,当类的类型不足以鉴别一个依赖的时候会使用到。如果我们没有去区分,会报错:xxx cannot be provided
without an @Provides-annotated method。例如上面的Person类,我们现在准备返回两个:小明与小关,返回的都是Person类,怎么区分依赖?

首先自定义一个
@Qualifier

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface User {
}


下来是Module:
@Module
public class UserModule {

@Provides
@User//加上这个自定义注解用于区分
Login provideXiaoMingUser() {
Login xiaomin = new Login();
xiaomin.setPassword("******");
xiaomin.setName("小明");
return xiaomin;
}
@Provides
Login provideXiaoGuanUser() {
Login xiaoguan = new Login();
xiaoguan.setPassword("######");
xiaoguan.setName("小关");
return xiaoguan;
}
}


Component:
@Subcomponent(modules = {
UserModule.class
})
public interface UserComponent {
void inject(SecondActivity mSecondActivity);
}


这里用到了
@Subcomponent
,我们想复用组件时,可以使用它,下面是父组件使用方法。另一种是注解属性添加dependencies。
@Singleton
@Component(
modules ={ AppModule.class
}
)
public interface AppComponent {

Context getAppContext();
UserComponent createUserComponent(UserModule userModule);
}


这种复用组件其实是在在父组件中创建了子组件的内部类。如下:
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerAppComponent implements AppComponent {
private Provider<Context> provideContextProvider;

private DaggerAppComponent(Builder builder) {
assert builder != null;
initialize(builder);
}

public static Builder builder() {
return new Builder();
}

private void initialize(final Builder builder) {
this.provideContextProvider = ScopedProvider.create(AppModule_ProvideContextFactory.create(builder.appModule));
}

@Override
public Context getAppContext() {
return provideContextProvider.get();
}

@Override
public UserComponent createUserComponent(UserModule userModule) {
return new UserComponentImpl(userModule);
}

public static final class Builder {
private AppModule appModule;

private Builder() {
}

public AppComponent build() {
if (appModule == null) {
throw new IllegalStateException("appModule must be set");
}
return new DaggerAppComponent(this);
}

public Builder appModule(AppModule appModule) {
if (appModule == null) {
throw new NullPointerException("appModule");
}
this.appModule = appModule;
return this;
}
}

private final class UserComponentImpl implements UserComponent {//内部类
private final UserModule userModule;
private Provider<Login> provideXiaoMingUserProvider;
private Provider<Login> provideXiaoGuanUserProvider;
private MembersInjector<SecondActivity> secondActivityMembersInjector;

private UserComponentImpl(UserModule userModule) {
if (userModule == null) {
throw new NullPointerException();
}
this.userModule = userModule;
initialize();
}

private void initialize() {
this.provideXiaoMingUserProvider = UserModule_ProvideXiaoMingUserFactory.create(userModule);
this.provideXiaoGuanUserProvider = UserModule_ProvideXiaoGuanUserFactory.create(userModule);
this.secondActivityMembersInjector = SecondActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideXiaoMingUserProvider, provideXiaoGuanUserProvider);
}

@Override
public void inject(SecondActivity mSecondActivity) {
secondActivityMembersInjector.injectMembers(mSecondActivity);
}
}
}


初始化:(MyApplication中)
mAppComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
mUserComponent = mAppComponent.createUserComponent(new UserModule());


调用:
public class SecondActivity extends AppCompatActivity {

UserComponent userComponent;

@Inject
@User
Login xiaoming;

@Inject
Login xiaoguan;

@Bind(R.id.button4)
Button mButton4;

@Bind(R.id.button5)
Button mButton5;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
ButterKnife.bind(this);
userComponent = ((MyApplication)this.getApplication()).getUserComponent();
userComponent.inject(this);
}
@OnClick({
R.id.button4,
R.id.button5,
})
void onButtonClicked(View v) {
switch (v.getId()) {
case R.id.button4:
Toast.makeText(this,
xiaoming.getName() + "----" + xiaoming.getPassword(),Toast.LENGTH_SHORT).show();
break;
case R.id.button5:
Toast.makeText(this,
xiaoguan.getName() + "----" + xiaoguan.getPassword(),Toast.LENGTH_SHORT).show();
break;
}
}
}


具体生成的代码,大家下载Demo后自行查看。

通过自动生成的代码可以看出Dagger 2主要用到了Builder模式、Factory模式,代码不难理解。同时因为Dagger 2没有使用反射,虽然效率提高了,但是缺乏灵活性。这也是为了提高效率的代价。


3.Dagger2 练习Demo

Demo下载链接:Dagger2Example

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: