一、Dagger2简介
Dagger2是google的一款依赖注入框架,前身是square公司开发的dagger1,适用于Android和Java应用程序的开发。
Dagger2提供给Java和Android使用,主要用于模块间解耦、提高代码的可维护性和代码的可测试性,是一款依赖注入框架,使用了IOC(控制反转)的思想,在编译阶段使用APT或kapt利用注解生成Java代码,然后结合部分手写代码来完整依赖注入工作。Dagger1通过反射实现的,而Dagger2则是编译阶段生成代码实现。
二、 Dagger2注解
1、@Inject
有两种用处,一表明需求方,用来标注需要获取依赖对象的属性或函数中参数,下面例子FirstActivity需要依赖Book。二表明提供方,用来标注构造方法,Dagger2通过@Inject
注解可以在需要这个类实例的时候来找到这个构造函数并把相关实例构造出来,以此来为被@Inject
标记了的变量提供依赖,同时会在build下生成对应的xxx_Factory类,具体看后面详解。
scala
public class FirstActivity extends AppCompatActivity {
@Inject
Book book;
...
}
public class Book {
@Inject
public Book() {
}
}
2、@Module
用来标注提供依赖对象的类,类似于媒人。Module类中会有一个方法来提供依赖对象,在这个方法中可以对注入对象的有参构造函数传入参数或者进行其他处理,该方法一般会被@Provides
注解修改。
kotlin
@Module
//@Singleton
class ServiceModule {
// @Singleton
@Provides
fun provideService() = HttpClient.getInstance().getService(ApiService::class.java, Constants.BASE_URL)
}
3、@Provides
用来标注Module类中的提供依赖对象的方法进行标注,该方法在需要提供依赖时被调用,从而把提供好的对象当做依赖给标注了@Inject 的变量赋值。被@Module
和@Provides
标注的类在build下会生成对应的xxxModule_xxxFactory类。
4、@Component
用来标注接口,该接口提供了方法用来传入业务层,是业务层和Module之间的连接器。标注后会在build下生成DaggerxxxComponent类。
less
@Singleton
@Component(
modules = [
ServiceModule::class
]
)
interface AppComponent {
fun injectService(repository : HomeRepository)
}
5、 @Singleton
. 默认情况下,@Inject
获取到的依赖对象是非单例的,要想实现单例,需要用@Singleton
对Module中的provide方法和Conponent接口进行标注。
三、 Dagger2使用
1、添加gradle依赖
arduino
implementation 'com.google.dagger:dagger-android:2.51.1'
kapt 'com.google.dagger:dagger-compiler:2.51.1'
2、添加代码,分别创建依赖对象类、module、component、代码调用注入部分
java
public class Book {
@Inject
public Book() {
}
}
@Module
public class BookModule {
@Provides
public Book provideBook() {
return new Book();
}
}
@Component(modules = BookModule.class)
public interface BookComponent {
void injectFirstActivity(FirstActivity activity);
void injectSecondActivity(SecondActivity activity);
}
创建两个Activity,通过`@Inject`获取两个依赖注入对象Book,并打印两个Book。
public class FirstActivity extends AppCompatActivity {
private static final String TAG = "First";
@Inject
Book book;
@Inject
Book book2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
//DaggerBookComponent是由dagger-compiler通过APT自动生成的
DaggerBookComponent.builder()
.bookModule(new BookModule())
.build().injectFirstActivity(this);
//另个Book的hashCode不一样,说明Dagger2提供的Book默认是非单例的
Log.d(TAG, "book: " + book.hashCode());
Log.d(TAG, "book2: " + book2.hashCode());
findViewById(R.id.button).setOnClickListener(v ->
startActivity(new Intent(this, SecondActivity.class))
);
}
}
public class SecondActivity extends AppCompatActivity {
private static final String TAG = "Second";
@Inject
Book book;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
DaggerBookComponent.builder()
.bookModule(new BookModule())
.build().injectSecondActivity(this);
Log.d(TAG, "book: " + book.hashCode());
}
}
通过log可以看出3个Book对象的是不同的,可见通过Dagger2默认获取到的依赖注入对象是非单例的。 3、局部单例 首先在Module的provide方法上加上@Singleton
,需要注意的是之前版本的Dagger2需要在Module类上也添加@Singleton
注解,新版本的已经不需要。
java
/**
* 若想依赖对象是单例,需要加上@Singleton注解。最新版本的Dagger2已经不需要在Module上添加@Singleton注解(不然编译会报错),只需要在下面的provider上添加@Singleton即可。
*/
@Module
public class BookModule {
@Singleton
@Provides
public Book provideBook() {
return new Book();
}
}
然后在Component类上添加`@Singleton`注解。
@Singleton
@Component(modules = BookModule.class)
public interface BookComponent {
void injectFirstActivity(FirstActivity activity);
void injectSecondActivity(SecondActivity activity);
}
重新编译后运行,可以看到FirstActivity中的两个Book的hashCode是相同的,SecondActivity和FirstActivity中的Book对象hashCode是不一样的,可见实现了局部单例。 4、全局单例,需要借助全局保存DaggerxxxComponent对象。 在上边的基础上继续做修改,创建Application,在Application中实例化Component对象,并提供获取Component的方法。
scala
public class MyApplication extends Application {
private BookComponent mBookComponent;
@Override
public void onCreate() {
super.onCreate();
mBookComponent = DaggerBookComponent.builder()
.bookModule(new BookModule())
.build();
}
public BookComponent getBookComponent() {
return mBookComponent;
}
}
然后在Activity中通过Application去获取Component。
public class FirstActivity extends AppCompatActivity {
private static final String TAG = "First";
@Inject
Book book;
@Inject
Book book2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
//在Application中获取Component,实现全局单例
((MyApplication) getApplication()).getBookComponent().injectFirstActivity(this);
//两个Book的hashCode一致。
Log.d(TAG, "book: " + book.hashCode());
Log.d(TAG, "book2: " + book2.hashCode());
findViewById(R.id.button).setOnClickListener(v ->
startActivity(new Intent(this, SecondActivity.class)));
}
}
public class SecondActivity extends AppCompatActivity {
private static final String TAG = "Second";
@Inject
Book book;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
((MainApplication) getApplication()).getBookComponent().injectSecondActivity(this);
//SecondActivity和FirstActivity中的Book的hashCode一致。
Log.d(TAG, "book: " + book.hashCode());
}
}
查看Log可以发现两个页面的3个Book是同一个,那就实现了全局单例。
四、原理初步
typescript
// Generated by Dagger (https://dagger.dev).
package com.cding.dagger.app;
import com.cding.dagger.app.activity.FirstActivity;
import com.cding.dagger.app.activity.FirstActivity_MembersInjector;
import com.cding.dagger.app.activity.SecondActivity;
import com.cding.dagger.app.activity.SecondActivity_MembersInjector;
import dagger.internal.DaggerGenerated;
import dagger.internal.Preconditions;
@DaggerGenerated
@SuppressWarnings({
"unchecked", "rawtypes"
})
public final class DaggerBookComponent implements BookComponent {
private final BookModule bookModule;
private final DaggerBookComponent bookComponent = this;
private DaggerBookComponent(BookModule bookModuleParam) {
this.bookModule = bookModuleParam;
}
public static Builder builder() {
//1 使用构造者模式实例化DaggerBookComponent对象
return new Builder();
}
public static BookComponent create() {
return new Builder().build();
}
@Override
public void injectFirstActivity(FirstActivity activity) {
injectFirstActivity2(activity);
}
@Override
public void injectSecondActivity(SecondActivity activity) {
injectSecondActivity2(activity);
}
private FirstActivity injectFirstActivity2(FirstActivity instance) {
//4 Activity中的@Inject生成injectBook方法,通过BookModule_ProvideBookFactory来获取依赖注入对象
FirstActivity_MembersInjector.injectBook(instance, BookModule_ProvideBookFactory.provideBook(bookModule));
FirstActivity_MembersInjector.injectBook2(instance, BookModule_ProvideBookFactory.provideBook(bookModule));
return instance;
}
private SecondActivity injectSecondActivity2(SecondActivity instance) {
SecondActivity_MembersInjector.injectBook(instance, BookModule_ProvideBookFactory.provideBook(bookModule));
return instance;
}
public static final class Builder {
private BookModule bookModule;
private Builder() {
}
//2 传入一个BookModule对象
public Builder bookModule(BookModule bookModule) {
this.bookModule = Preconditions.checkNotNull(bookModule);
return this;
}
//3 实例化DaggerBookComponent
public BookComponent build() {
if (bookModule == null) {
this.bookModule = new BookModule();
}
return new DaggerBookComponent(bookModule);
}
}
}
java
// Generated by Dagger (https://dagger.dev).
package com.cding.dagger.app;
import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.Preconditions;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
@ScopeMetadata
@QualifierMetadata
@DaggerGenerated
@SuppressWarnings({
"unchecked",
"rawtypes"
})
public final class BookModule_ProvideBookFactory implements Factory<Book> {
private final BookModule module;
public BookModule_ProvideBookFactory(BookModule module) {
this.module = module;
}
@Override
public Book get() {
return provideBook(module);
}
public static BookModule_ProvideBookFactory create(BookModule module) {
return new BookModule_ProvideBookFactory(module);
}
//5 通过BookModule拿到Book对象,并用Dagger2提供的Preconditions.checkNotNullFromProvides()方法来检查获取到的对象是否为空
public static Book provideBook(BookModule instance) {
return Preconditions.checkNotNullFromProvides(instance.provideBook());
}
}
java
// Generated by Dagger (https://dagger.dev).
package com.cding.dagger.app.activity;
import com.cding.dagger.app.Book;
import dagger.MembersInjector;
import dagger.internal.DaggerGenerated;
import dagger.internal.InjectedFieldSignature;
import dagger.internal.QualifierMetadata;
import javax.inject.Provider;
@QualifierMetadata
@DaggerGenerated
@SuppressWarnings({
"unchecked",
"rawtypes"
})
public final class FirstActivity_MembersInjector implements MembersInjector<FirstActivity> {
private final Provider<Book> bookProvider;
private final Provider<Book> book2Provider;
public FirstActivity_MembersInjector(Provider<Book> bookProvider, Provider<Book> book2Provider) {
this.bookProvider = bookProvider;
this.book2Provider = book2Provider;
}
public static MembersInjector<FirstActivity> create(Provider<Book> bookProvider,
Provider<Book> book2Provider) {
return new FirstActivity_MembersInjector(bookProvider, book2Provider);
}
@Override
public void injectMembers(FirstActivity instance) {
injectBook(instance, bookProvider.get());
injectBook2(instance, book2Provider.get());
}
@InjectedFieldSignature("cn.zhangmushui.dagger.demo1.activity.FirstActivity.book")
public static void injectBook(FirstActivity instance, Book book) {
//6 将获取到的Book对象赋值给Activity中的book
instance.book = book;
}
@InjectedFieldSignature("cn.zhangmushui.dagger.demo1.activity.FirstActivity.book2")
public static void injectBook2(FirstActivity instance, Book book2) {
instance.book2 = book2;
}
}
Dagger2原理是通过Dagger生成辅助类,在业务层需要获取依赖对象的地方使用@Inject去标注对象,就可以交给Dagger2的这些辅助类去实例化对象,起到了解耦的作用,提高了代码的可读性和可维护性和可测试性。