使用 Dagger 库 基础篇
Dagger 注入对象的原理
Dagger 是一个依赖注入的库,采用编译时生成代码的方式实现,现在的版本是 2.11。
Dagger 涉及的概念很多,为了避免过早的陷入细节,这篇文章先通过一个例子,介绍 Dagger 库基本的 @Inject
, @Component
, @Module
几个知识点。
下面我们就看看如何用 Dagger 造个凳子(图片来源于 Muji 官网):
Stool.jpg注:这个 Muji 家的凳子和我们经常看到的条凳很相似,相关背景可以看知乎上的问题。选用这个凳子纯粹是因为该款式结构简单,便于拆分。
我们在这篇文章中将凳子作为一个整体考虑,直接创建凳子对象。
传统方法创建被依赖对象
首先,创建被依赖的类 Stool :
public class Stool {
public Stool() {
}
}
MainActivity 需要(依赖)这个对象,所以有一个 Stool 成员变量,并且我们在适当时机 new 一个对象:
public class MainActivity extends AppCompatActivity {
Stool mStool;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mStool = new Stool();
}
}
这样写很符合习惯,但是造成了紧耦合。关于这部分知识,请参考这篇文章。
那么接下来演示下,如何用 Dagger 最简单的方式创建一个对象。
使用 Dagger 创建被依赖对象 (@Inject 方式)
首先,在 app 的 build.gradle 加入 Dagger 库 :
dependencies {
...
compile 'com.google.dagger:dagger:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
}
在被依赖的类 Stool 的构造函数上加上 @Inject
注解,表示我可以提供这个对象:
public class Stool {
@Inject
public Stool() {
}
}
相应的,MainActivity 的 Stool 成员变量也要加上 @Inject
注解,表示我需要这个对象:
public class MainActivity extends AppCompatActivity {
@Inject
Stool mStool;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
如果这样就结束了,那就太简单了。但实际上完成上述步骤,只是有了需求者和提供者,还需要有一个运送者负责传递。这个任务是由 Dagger 最重要的 Component 接口完成:
@Component()
public interface MainActivityComponent {
void inject(MainActivity activity);
}
在接口前加上 @Component() 标注,告诉 Dagger 这是一个 Component 接口。同时,接口方法任意命名(通常约定俗成是 inject ),只不过需要传入要注入的目的地:MainActivity 对象。
然后,Dagger 预编译器会根据这个接口自动加上 Dagger- 前缀,生成一个实现类 DaggerMainActivityComponent。
如果没有生成对应的代码,需要在 Android Studio 点击 Build -> Rebuild Project。
上述步骤搭好了架子,最后还需要手动输入,决定注入的时机。这里就在 onCreate 注入 Stool 对象,再次修改 MainActivity,添加DaggerMainActivityComponent.create().inject(this)
:
public class MainActivity extends AppCompatActivity {
@Inject
Stool mStool;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.create().inject(this);
}
}
自动生成的类 DaggerMainActivityComponent 采用了 Builder 模式(关于这部分分析,可以参考接下来讲述原理的文章)。所以通常的教程会看到
DaggerMainActivityComponent.builder().build()
的方式创建 Component 对象,实际上create()
封装了builder().build()
方法,所以用DaggerMainActivityComponent.create()
创建 Component 对象效果相同。
如上就是采用 Dagger 最基本的方式创建并注入一个凳子对象。涉及的知识点包括:@Inject
注解和 @Component
接口。
使用 Dagger 创建被依赖对象 (@Module 方式 + static 方法)
接下来我们用 @Module
方式创建对象,引入 @Module
源于有些时候无法在构造函数添加 @Inject
注解。
这次,被依赖的类 Stool 构造函数没有 @Inject
注解:
public class Stool {
public Stool() {
}
}
然后添加 StoolModule 类,用于创建 Stool 依赖对象:
import dagger.Module;
import dagger.Provides;
@Module
public class StoolModule {
@Provides
static Stool provideStool() {
return new Stool();
}
}
@Module
标注说明这个类可以提供依赖,@Provides
在 @Module
中使用,说明标注的方法可以返回依赖。
由于采用了 Module 方式创建被依赖对象,Component 接口也需要做出些修改:
@Component(modules = StoolModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}
在 @Component
注解中,定位到之前定义的 StoolModule 类 (modules = StoolModule.class)
,表示采用这个类提供依赖对象。
此处 MainActivity 保持原样:
public class MainActivity extends AppCompatActivity {
@Inject
Stool mStool;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.create().inject(this);
}
}
可以看到,通过引入 @Module
,并在 @Component
指定,完全可以平滑的替代在构造函数前加 @Inject
的方式创建依赖对象。
这回涉及的知识点包括:@Module
注解和 @Component
接口指定 Module 。
但是,在自动生成的 DaggerMainActivityComponent
类中发生了些改变,采用 Module 方式会在其中增加一个 @Deprecated
方法:
@Deprecated
public Builder stoolModule(StoolModule stoolModule)
这个方法在这个例子中没有什么作用。因为我们在 StoolModule 中定义的是一个静态方法,并不需要传递一个 StoolModule 对象:
@Provides
static Stool provideStool()
所以,会增加 @Deprecated
标注。这个标注会出现的原因,可以参看官方文档:Unused Modules and Component Dependencies :
- 如果 Module 的方法是 static , Dagger 并不需要这个对象,可以直接调用静态方法
- 如果一个 Module 未和 Component 关联起来 (例如,我们没有在 MainActivity 的成员变量前加
@Inject
注解 ),也没有必要创建这个 Module 对象。
使用 Dagger 创建被依赖对象 (@Module 方式 + 非 static 方法)
这里我们将 Module 改为非 static 方法创建 Stool 依赖对象:
import dagger.Module;
import dagger.Provides;
@Module
public class StoolModule {
@Provides
Stool provideStool() {
return new Stool();
}
}
此时 MainActivity 可以保持原样,也可以采用 Builder 模式手动创建并传递 Module 对象。如果没有传递, DaggerMainActivityComponent
在调用 build()
方法时会自动创建:
public class MainActivity extends AppCompatActivity {
@Inject
Stool mStool;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.create().inject(this);
//DaggerMainActivityComponent.builder()
// .stoolModule(new StoolModule()).build().inject(this);
}
}
关于这部分原理,可以参考接下来的文章。
综上,Dagger 中频繁出现的几个知识点就介绍完了。在后续的文章中,会进一步完善这个程序,并分析 Dagger 工作的原理。
网友评论