0x00.前言
Dagger2学习之配置和基础使用(一)中展示了最基本的Dagger2的应用。
在实际开发中有可能会出现两种情况,使用现在所掌握的技术手段是无法解决的。
1.有的时候有可能使用第三方的jar包。但是我们不可能在第三方jar包上写”@Inject”
2.构造函数可能需要传入参数。
正对以上的情况”@Module”就横空出世了。
0x01.Module类的应用
Module类:
@Module
public class ActivityModule {
@Provides
public User provideUser() {
return new User();
}
}
Module类实现起来很简单,在实现好的实体类上加上”@Module”和”@Provides”。它本质上是一个工厂类。这个类替代了在文章Dagger2学习之配置和基础使用(一)中在User类的构造函数上的”@Inject”,那为什么要使用这个Module类来替代呢?
聪明的你一定知道是为了解决文章开头的那两个问题。解决的重点是”@Provides”和对应的provideUser方法。这样,无论是第三方框架还是自己写的代码,都可以放到”provideUser”中去。那么需要通过构造函数传递参数该怎么办?当然有办法,我们只需要在”provideUser”方法上传入参数类似下面的代码:
@Provides
public User provideUser(int age) {
return new User(age);
}
// 或者这样
@Provides
public User provideUser(int age) {
User user = new User();
user.setAge(age);
return user;
}
// 这样可以覆盖所有需要传入参数的场景
当然,如果仅仅这样还是不行的。因为很明显,这里的方法参数是在哪里传入的呢,它并不是凭空出现的。
这里先给出Component代码:
@Component
public interface ActivityComponent {
void inject(MainActivity daggerActivity);
}
注入到MainActivity的代码
public class MainActivity extends AppCompatActivity {
//注入
@Inject
User user;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
inject();
Log.v("tag", "user.name::"+user.name);
}
//注入行为
private void inject() {
DaggerActivityComponent.create().inject(MainActivity.this);
}
上面不是提到的参数是如何传入的呢?其实只需要改造下
DaggerActivityComponent.create().inject(MainActivity.this);
代码即可,代码如下:
DaggerActivityComponent.builder()
.activityModule(new ActivityModule(23))// 在这里传入需要的参数
.build()
.inject(this);
这样,就彻底的解决了上面的两个问题。
0x02.关于Component
上一篇文章由于只是介绍最基本应用,没有介绍Component。那么在这里介绍下Component。
正如前面一篇文章说的。Component可以看成是医生使用的注射器,也可以看成是一个连接注入类和目标类的一个连接。
基本用法
首先新建立一个java接口,在接口上加上@Component。再在接口中提供一个抽象方法即可。
@Component
public interface ActivityComponent {
void inject(MainActivity activity);
}
当然以上的代码是最简单的一种。
在使用了Module之后,需要在@Component通过”modules”来注明,你使用的是哪个Module。
@Component(modules = ActivityModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
}
这样就可以在注入类和目标类建立一个联系。虽然这里实现了一个接口,但是实际上是通过dagger插件,生成java代码。生成的部分代码如下(上面已经加了注释):
/**
*DaggerActivityComponent实现ActivityComponent
*这里采用了类似构建者模式
*/
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerActivityComponent implements ActivityComponent {
private Provider<User> provideUserProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerActivityComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
// 返回Builder类
public static Builder builder() {
return new Builder();
}
// 初始化
private void initialize(final Builder builder) {
this.provideUserProvider = new Factory<User>() {
private final AppComponent appComponent = builder.appComponent;
@Override public User get() {
User provided = appComponent.provideUser();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable component method");
}
return provided;
}
};
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideUserProvider);
}
// 注入
@Override
public void inject(MainActivity activity) {
mainActivityMembersInjector.injectMembers(activity);
}
// 最重要的Builder,构建者
public static final class Builder {
private ActivityModule activityModule;
private AppComponent appComponent;
private Builder() {
}
// 返回ActivityComponent对象。
// 同时,在构造函数中传入Builder对象。
public ActivityComponent build() {
if (activityModule == null) {
throw new IllegalStateException("activityModule must be set");
}
if (appComponent == null) {
throw new IllegalStateException("appComponent must be set");
}
return new DaggerActivityComponent(this);
}
// 传入的ActivityModule参数
public Builder activityModule(ActivityModule activityModule) {
if (activityModule == null) {
throw new NullPointerException("activityModule");
}
this.activityModule = activityModule;
return this;
}
// ................
}
}