博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Dagger2使用攻略
阅读量:6484 次
发布时间:2019-06-23

本文共 20301 字,大约阅读时间需要 67 分钟。

Dagger2使用攻略

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

1.Gradle配置

(1)须要配置apt 插件:(在project根文件夹build.gradle文件里加入例如以下代码)

dependencies {        ...        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'    }

(2)加入依赖:(在modulebuild.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条依赖的原因參考:

● 假设在项目中同一时候用了Butterknife,在Build时会报凝视冲突。

这里写图片描写叙述

解决方法:(在modulebuild.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
{
private final MembersInjector
supertypeInjector; private final Provider
mPersonProvider; public MainActivity_MembersInjector(MembersInjector
supertypeInjector, Provider
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
create(MembersInjector
supertypeInjector, Provider
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在哪里能够找到依赖。

@Modulepublic 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, 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
provideSharedPreferencesProvider; private Provider
provideScheduleProvider; private Provider
storageProvider; private MembersInjector
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
{
private final MembersInjector
supertypeInjector; private final Provider
mPreferencesProvider; private final Provider
mPersonProvider; public MainActivity_MembersInjector(MembersInjector
supertypeInjector, Provider
mPreferencesProvider, Provider
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
create(MembersInjector
supertypeInjector, Provider
mPreferencesProvider, Provider
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
mScheduleImpl;//Lazy 类 private final String KEY = "Dagger 2"; @Inject public Storage(SharedPreferences mPreferences ,Lazy
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:

@Modulepublic 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
providePersonProvider; private Provider
provideLoginProvider; private MembersInjector
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
implements Provider
{
private static final Object UNINITIALIZED = new Object(); private final Factory
factory; private volatile Object instance; private ScopedProvider(Factory
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
Provider
create(Factory
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:

@Modulepublic 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
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
provideXiaoMingUserProvider; private Provider
provideXiaoGuanUserProvider; private MembersInjector
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下载链接:

这里写图片描写叙述

4.參考

1.

2.

3.

4.


PS:最后说一下,关于Dagger2的学习成本还是挺高的。我自己也是从零開始接触。利用业余时间前前后后用了近一周时间去学习,一開始看的也是云里雾里。

事实上对比着自己主动生成的代码多看看就比較好理解了。有什么错误地方。希望多多交流。就这样。

。。

你可能感兴趣的文章
Java集合总结【面试题+脑图】,将知识点一网打尽!
查看>>
java基础(十) 数组类型
查看>>
小程序 Canvas绘图不同尺寸设备 UI兼容的两个解决方案
查看>>
产品规划,你通常规划多久的时间线?
查看>>
Android-MVP架构
查看>>
HTML5前端教程分享:CSS浏览器常见兼容问题
查看>>
Material Design之AppBarLayout
查看>>
让mysql不能为空的字段为空时也能插入
查看>>
一服多开
查看>>
从CVS迁移到SVN
查看>>
总部与前线
查看>>
微软推出Windows 10专业教育版:Cortana没了
查看>>
TensorFlow教程之API DOC 6.1.2Class tensorflow::EnvWrapper
查看>>
多目标跟踪突破:上交大&中兴 MOT Challenge 测评获第一
查看>>
控制ASP.NET Web API 调用频率
查看>>
系统诊断小技巧(7):利用Iptables进行排查和诊断的简易方案
查看>>
IPv6的渗透率比人们想象的要快速?
查看>>
针对Windows零日漏洞,微软是不是太过“无作为”了?
查看>>
推特解散商业团队 终止开发“Buy”按钮
查看>>
英特尔SSD:17年将专注于3D NAND和PCIe
查看>>