Dagger2是由google接手的*** dependency injection***(依赖注入)框架,今天我们来拨开dagger2的迷雾。这篇文章主要介绍Dagger2的简单用法,内容包括
- @Inject
- @Component
- @Module
- @Provides
- @Singleton
首先来看下@Inject ,先看一段代码
public class User {
@Inject
public User () { };
@Inject
public void setName ( ){}
.......
}
public class UserActivity extends AppCompatActivity {
......
@Inject User user;
......
}
该注解作用域有三个:
- 属性
@Inject User user
@Inject 表明这里需要一个User类实例,由Dagger2 完成赋值,注意:该属性作用域必须为 public
- 方法
@Inject public void setName ( ){}
** @Inject 在这里的作用是:当构造函数完成后,立即调用该函数,一般用来调用参数为 this 的方法**
- 构造函数
@Inject
public User () { };
@inject 标记这是一个被依赖的类,Dagger2 负责生成这个类的实例。需要注意的是,如果构造函数有参数,那么参数的构造方法也必须有@Inject 标记,直到某个参数的构造函数不需要参数
@Component
@Component
public interface IUserComponent {
User getUser () ;
void inject (UserActivity activity) ;
}
Component 是连接依赖方与被依赖方的桥梁,而且类型必须为接口或者抽象类,插件会自动生成该类的实例,名字一般为Dagger+该接口/抽象类。该接口一般有两种方法:
- 提供被依赖类
object getObjecet() //对应上面 getUser ( ) 提供被依赖类
- 注入依赖类
/**
*比如上面 UserActivity 依赖 User,
*UserActivity 就象一个容器,由Dagger 注入 User 实例
*/
void inject ( 目标容器)
编译一下,插件会自动生成Dagger*Component实体类,
我们只需在UserActivity 中使用一行代码便可完成注入,具体注入下文有说到。
@Override
public void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerIUserComponent.builder().build().inject(this);
}
@Module
Module 的作用也是提供依赖类,那么 Inject 和 Module 有什么区别呢?
Inject主要用于我们自己创建的类,或者说我们可以改变其构造函数的类,比如,如果你的构造函数是这样的:
...
@Inject
public User (String name) {......}
...
上面我们就提过,对于有参数的构造函数,其参数的构造函数也必须有@Inject标记,显然,我们无法对String的构造函数进行更改。
这时候就需要@Module。Module可以给不能修改源码的类提供依 赖,当然,能用Inject标注的通过Module也可以提供依赖我们更改下部分代码:
...
public class User {
@Inject
public User (String name) { };
}
...
@Component (modules = UserModule.class)
public interface IUserComponent {
void inject(UserActivity activity);
User getUser();
}
.....
@Module
public class UserModule {
private String name;
public UserModule(String name){
this.name = name;
}
@Provides
User provideUser() {return new User(name);}
}
我们新建一个Module类,然后在@Component后面指定范围 (modules = UserModule.class),这提醒Dagger 到 UserModule 获取User实例
@Provides
用Provide来标注一个方法,该方法可以在需要提供依赖类时被调用,provide主要用于标注Module里的方法。
编译一下,看下生成代码:
public final class DaggerIUserComponent implements IUserComponent {
private Provider provideUserProvider;
private MembersInjector userActivityMembersInjector;
private DaggerIUserComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideUserProvider = UserModule_ProvideUserFactory.create(builder.userModule);
this.userActivityMembersInjector = UserActivity_MembersInjector.create(provideUserProvider);
}
@Override
public void inject(UserActivity activity) {
userActivityMembersInjector.injectMembers(activity);
}
@Override
public User getUser() {
return provideUserProvider.get();
}
public static final class Builder {
private UserModule userModule;
private Builder() {}
public IUserComponent build() {
if (userModule == null) {
throw new IllegalStateException(UserModule.class.getCanonicalName() + " must be set");
}
return new DaggerIUserComponent(this);
}
public Builder userModule(UserModule userModule) {
this.userModule = Preconditions.checkNotNull(userModule);
return this;
}
}
}
可以看到有两个变量provideUserProvider,userActivityMembersInjector。
看下inject 函数 ,userActivityMembersInjector调用injectMembers(UserActivity acativity)函数
@Override
public void injectMembers(UserActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.user = userProvider.get(); //关键代码,完成注入
}
我们很清楚的看到Dagger通过直接对变量的引用实现代码注入,这也是为什么变量的作用域必须是 public,这时又有一个新变量userProvider,我们看下它的来历。
public final class UserActivity_MembersInjector {
......
public UserActivity_MembersInjector(Provider userProvider) {
assert userProvider != null;
this.userProvider = userProvider;
}
......
public static MembersInjector create(Provider userProvider) {
return new UserActivity_MembersInjector(userProvider);
}
}
它是做参数传入构造器的,我们来看下什么时候传入的参数
public final class DaggerIUserComponent implements IUserComponent {
private void initialize(final Builder builder) {
......
this.provideUserProvider = UserModule_ProvideUserFactory.create(builder.userModule);
this.userActivityMembersInjector = UserActivity_MembersInjector.create(provideUserProvider);
}
......
}
又涉及到一个新类UserModule_ProvideUserFactory
public final class UserModule_ProvideUserFactory implements Factory {
private final UserModule module;
public UserModule_ProvideUserFactory(UserModule module) {
assert module != null;
this.module = module;
}
@Override
public User get() {
return Preconditions.checkNotNull(
module.provideUser(), "Cannot return null from a non-@Nullable @Provides method");
}
......
它接受一个UserModule作为参数。在get()中调用Module的方法,实现依赖类的注入。
所以我们在UserActivity中可以很轻松的实现注入
DaggerIUserComponent.builder()
.userModule(new UserModule("name"))
.build()
.inject(this);
@Singleton
我们来看下@Singleton使用:
我们改下代码
@Module
public class UserModule {
......
@Provides
@Singleton //添加注解
User provideUser() {return new User(name);}
.....
}
/**
*同时修改Component
*/
@Component (modules = UserModule.class)
@Singleton
public interface IUserComponent {
void inject(UserActivity activity);
User getUser();
}
......
public class UserActivity extends AppCompatActivity {
@Inject
public User user;
@Inject User user1; //增加一个变量
@Override
public void onCreate (Bundle savedInstanceState){
......
Log.e("TAG",user.hashCode() +"---"+user1.hashCode()); //打印哈希值
}
}
我们很清楚的看到,两个引用的哈希值一样,证明两个引用指向同一对象,说明使用 @Singleton标记,和我们使用单例模式是一样的。
以上就是这篇文章的全部内容,谢谢观赏。
参考资料:
浅析Dagger2的使用