一、简述
Dagger2是一个Android目前较为主流的依赖注入框架,最早的版本Dagger1 由Square公司开发,现在Dagger2由谷歌接手开发,主要用于模块间解耦,提高代码的健壮性和可维护性。之前也断断续续看过好多文章,今天正式学习一下。并且额外介绍下如何在Kotlin中使用Dagger2,写的不好,还请见谅!
二、注解方法
@Inject
: 通常在需要依赖的地方使用这个注解。换句话说,你用它告诉Dagger这个类或者字段需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。@Module
: Modules类里面的方法专门提供依赖,所以我们定义一个类,用@Module
注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到需要的 依赖。modules的一个重要特征是它们设计为分区并组合在一起(比如说,在我们的app中可以有多个组成在一起的modules)。@Provides
: 在modules中,我们定义的方法是用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。@Component
: Components从根本上来说就是一个注入器,也可以说是@Inject
和@Module
的桥梁,它的主要作用就是连接这两个部分。Components可以提供所有定义了的类型的实例,比如:我们必须用@Component
注解一个接口然后列出所有的@Modules
组成该组件,如 果缺失了任何一块都会在编译的时候报错。所有的组件都可以通过它的modules知道依赖的范围。@Named
:当有多个构造方法时,可以使用@Named
进行标记区分@Scope
: Scopes可是非常的有用,Dagger2可以通过自定义注解限定注解作用域。后面会演示一个例子,这是一个非常强大的特点,因为就如前面说的一样,没必要让每个对象都去了解如何管理他们的实例@Singleton
:单例
三、入门例子
创建两个实例类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class MoneyController {
public MoneyController(String s) {
Log.e("TAG", "MoneyController: 构造方法======" + s);
}
public String payMoney() {
return "payMoney";
}
}
// -------------------------------------------------
public class OrderController {
String s;
public OrderController(String s) {
this.s = s;
}
public void order() {
Log.e("OrderController", "order" + s);
}
}创建Component,连接Module与Activity之间的桥梁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// @Modules 类似于我们的模块,提供各种实例跟对象
public class UserModule {
private Context mContext;
private String s;
public UserModule(Context context,String s) {
this.mContext = context;
this.s = s;
}
// @Provides 在Modules中,我们定义的方法是用这个注解,以此来告诉Dagger2我们想要提供哪些实例和对象
public OrderController providerOrderController() {
return new OrderController("lisi");
}
public MoneyController providerMoneyController() {
return new MoneyController(s);
}
}Inject注入
1
2
3
4
5// @Component:注入器,是@Inject和@Module的桥梁,它的主要作用就是连接这两个部分
public interface UserComponet {
void inject(DaggerActivity daggerActivity);
}在Activity中使用(需要先Rebuild一下,会自动生成一个Dagger开头的类)
1 |
|
- 如果UserModule中没有提供providerMoneyController这个方法可以怎么做呢?
它会自动调用MoneyController类中带有@Inject
注解的构造方法
四、区分不同实例
如果一个类有两个或多个构造方法该如何去区分使用呢?使用`@Named`
修改一下OrderController,给它添加一个构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class OrderController {
String s;
int age;
public OrderController(String s) {
this.s = s;
}
public OrderController(String s, int age) {
this.s = s;
this.age = age;
}
public void order() {
Log.e("OrderController", "order" + s);
}
public void age() {
Log.e("OrderController", "order" + s + "age" + age);
}
}修改
UserModule
,使用@Named
方法进行标记1
2
3
4
5
6
7
8
9
10
11
12
13// @Named 有多个构造方法时使用它标注不同的名字
// @Provides 在Modules中,我们定义的方法是用这个注解,以此来告诉Dagger2我们想要提供哪些实例和对象
public OrderController providerOrderController() {
return new OrderController("lisi");
}
public OrderController providerUserControllerNameAndAge() {
return new OrderController("lisi", 15);
}在Activity中也要这样子标注一下
1
2
3
4
5
6
OrderController orderController1;
OrderController orderController2;如果不满足这样子处理,可以参照源码加一个自定义注解
1
2
3
4
5
public Debug {
}用4中的注解取代
@Named("debug")
1
2
3
4
5
6
7
8
9
10
11
public OrderController providerOrderController() {
return new OrderController("lisi");
}
----------------
OrderController orderController1;
五、模块化的三种方式
假设单独创建一个网络请求的OkHttp模块,MoneyController需要使用这个OkHttpClient
1
2
3
4
5
6
7
8
9
public class HttpModule {
// 在这里创建OkHttpClient(应该是用单例的)
public OkHttpClient providerOkHttpClient(){
return new OkHttpClient().newBuilder().build();
}
}使用
@Module(includes = HttpModule.class)
引入1
2
3
4
5
6
7
8
9
10
11
public class UserModule {
... ...
// OkHttpClient来自HttpModule
public MoneyController providerMoneyController(OkHttpClient okHttpClient) {
return new MoneyController(okHttpClient);
}
}在Activity中使用
1
2
3
4DaggerUserComponet.builder()
.userModule(new UserModule(this))
.httpModule(new HttpModule()) //注意这个地方
.build().inject(this);第二种方法:可以将
HttpModule.class
添加到UserComponet的@Component
注解的modules中1
第三种方法是使用dependencies引入一个Component
1
六、在Kotlin中使用Dagger2(修改项目build)
1 | apply plugin: 'kotlin-kapt' |
七、全局单例(使用Kotlin实现)
声明:例子比较复杂,可以看源码(KotlinAndroidSamples),这里简要列举一下代码
AppComponent
1
2
3
4
5
6
7
8
9
10
11
)
interface AppComponent {
fun getContext(): App // 提供App的Context
fun getDataManager(): DataManager //数据中心
fun retrofitHelper(): RetrofitHelper //提供http的帮助类
}App(继承自Application)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class App : Application() {
// 伴生对象
companion object {
lateinit var appComponent: AppComponent
}
override fun onCreate() {
super.onCreate()
appComponent = DaggerAppComponent
.builder()
.appModule(AppModule(this))
.httpModule(HttpModule())
.build()
}
}在其它地方使用appComponent
1
2
3
4
5
6DaggerFragmentComponent
.builder()
.appComponent(App.appComponent)
.fragmentModule(FragmentModule(this))
.build()
.inject(this)FragmentComponent
1
2
3
4
5
6
7
8
class)) , modules = arrayOf(FragmentModule::
interface FragmentComponent {
val activity: Activity
fun inject(mingJiaFragment: MingJiaFragment)
}
八、源码地址
例子源码:https://github.com/sdwfqin/AndroidSamples
Kotlin例子源码:https://github.com/sdwfqin/KotlinAndroidSamples