Dagger2是一款基于 Java 注解来实现的彻底在编译阶段完成依赖注入的开源库。Dagger2 应于 Java 和 Android 开发而不仅仅是 Android,主要用于模块间解耦、提升代码的健壮性和可维护性。java
在app/build.gradle中的dependencies{ }加入如下代码同步便可:android
implementation 'com.google.dagger:dagger:2.23.1' annotationProcessor 'com.google.dagger:dagger-compiler:2.23.1'
dagger2三个重要组成部分为:module、component,、container,三者的关系以下图所示:json
因为Dagger2主要是编译期对注解内容进行获取,因此这三个组成部分也有相应的注解符号。app
Containeride
@Inject : 用于标记须要注入的依赖。函数
Modulegradle
@Module : 用该注解修饰的类,里面主要提供该依赖对象的实例化方法,方法名通常为provide + 对象名。ui
@Provides : 用这个来修饰@Module注解类中的方法,代表要提供的实例化对象this
Componetgoogle
@Componet : 能够理解为注入器,它会把目标类依赖的实例注入到目标类中。。
在构建好注解以后,项目须要rebuild一下,整个依赖注入的过程就算完成。
一、首先编写Person类,使用@Inject注解在构造函数上,用于标记须要注入的依赖。以下所示:
public class Person { private static final String TAG = "Person"; @Inject public Person() { } public void eat(){ Log.e(TAG, "eat...."); } }
二、接下来用@Component注解来完成依赖注入。咱们须要定义一个接口,接口命名建议为:目标类+Component,在编译后Dagger2就会为咱们生成名为Dagger+目标类名+Component的辅助类。具体代码以下所示:
@Component public interface MainActivityComponent { void inject(MainActivity activity); }
Component则能够理解为注入器,它会把目标类依赖的实例注入到目标类中。在这里须要定义inject方法,传入须要注入依赖的目标类。
三、在MainActivity中使用@Inject构建Person对象
public class MainActivity extends AppCompatActivity { @Inject Person person; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerMainActivityComponent.create().inject(this); person.eat(); } }
若是项目中使用了第三方的类库,能够采用@Module和@Provides来处理。咱们建立GsonModule类,以下所示:
@Module public class GsonModule { @Provides public Gson provideGson(){ return new Gson(); } }
@Module标注在类上,用来告诉Component,能够从这个类中获取依赖对象,也就是Gson类。
@Provodes 标记在方法上,表示能够经过这个方法来获取依赖对象的实例。
@Module标注的类其实就是一个工厂,用来生成各类类;@Provodes标记的方法,就是用来生成这些类的实例的。接着来编写Component类,以下所示:
@Component(modules = GsonModule.class) public interface MainActivityComponent { void inject(MainActivity activity); }
这和此前的区别就是加上了modules=GsonModule.class,用来指定Module。须要注意的是,Component 中能够指定多个Module。接下来在MainActivity中使用Gson,以下所示:
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Inject Gson gson; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerMainActivityComponent.create().inject(this); User user = new User("Legend", 31); String json = gson.toJson(user); Log.e(TAG, json); } }
其中,User类就是一个包含name和age的JavaBean,很是简单。
还有一种状况,当咱们使用依赖注入的时候,若是须要注入的对象是抽象的,则@Inject也没法使用,由于抽象的类并不能实例化。这时也能够采用@Module和@Provides。
一、定义一个Engine抽象类
public abstract class Engine { public abstract void work(); }
二、接着定义它的实现类GasolineEngine:
public class GasolineEngine extends Engine{ @Override public String work() { return "汽油发动机发动"; } }
三、随后在Car类中引用Engine,以下所示:
public class Car { private Engine engine; @Inject public Car(Engine engine) { this.engine = engine; } public String run(){ return engine.work(); } }
四、建立EngineModule类,以下所示:
@Module public class EngineModule { @Provides public Engine provideEngine(){ return new GasolineEngine(); } }
五、接着在Component中指定EngineModule:
@Component(modules = EngineModule.class) public interface MainActivityComponent { void inject(MainActivity activity); }
六、最后在MainActivity中使用,以下所示:
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Inject Car car; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerMainActivityComponent.create().inject(this); Log.e(TAG, car.run()); } }
@Qualifier 是限定符,@Named 则是@Qualifier 的一种实现。
当有两个相同的依赖时,它们都继承同一个父类或者均实现同一个接口。当它们被提供给高层时,Component 就不知
道咱们到底要提供哪个依赖 对象了,由于它找到了两个。
好比在上面的汽车例子中,若是咱们再提供一个DieselEngine给它, EngineModule能够改写为以下代码所示:
@Module public class EngineModule { @Provides @Named("Gasoline") public Engine provideGasoline(){ return new GasolineEngine(); } @Provides @Named("Diesel") public Engine provideDiesel(){ return new DieselEngine(); } }
给不一样的Provides定义不一样的@Named,接下来在Car类中指定要采用哪一种Provides:
public class Car { private Engine engine; @Inject public Car(@Named("Diesel") Engine engine) { this.engine = engine; } public String run(){ return engine.work(); } }
上面的例子也能够用@Qualifier来 实现,@Named传递的值只能是字符串;而@Qualifier则更灵活一些,@Qualifier不是直接标记在属性上的,而是用来自定义注解的,以下所示:
@Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface Gasoline { } @Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface Diesel { }
分别自定义两个注解@Gasoline和@Diesel,接下来修改EngineModule类,以下所示:
@Module public class EngineModule { @Provides @Gasoline public Engine provideGasoline(){ return new GasolineEngine(); } @Provides @Diesel public Engine provideDiesel(){ return new DieselEngine(); } }
最后在Car类指定须要哪一种依赖:
public class Car { private Engine engine; @Inject public Car(@Gasoline Engine engine) { this.engine = engine; } public String run(){ return engine.work(); } }
@Scope是用来自定义注解的,而@Singleton则是用来配合实现局部单例和全局单例的。
首先在 GsonModule 中添加@Singleton,以下所示:
@Module public class GsonModule { @Singleton @Provides public Gson provideGson(){ return new Gson(); } }
接下来在MainActivityComponent中添加@Singleton:
@Singleton @Component(modules = GsonModule.class) public interface MainActivityComponent { void inject(MainActivity activity); }
咱们在MainActivity中打印Gson的hashCode值,就会发现值是相同的,以下所示:
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Inject Gson gson; @Inject Gson gson1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerMainActivityComponent.create().inject(this); Log.e(TAG, gson.hashCode() + "--------" + gson1.hashCode()); } }
Gson 在 MainActivity 中是单例,若是在其余Activity中则再也不是单例的形式。(局部单例)
若是想要实现全局单例,就须要保证对应的Component只有一个实例。能够用@Singleton结合Application来实现:
@Scope @Retention(RetentionPolicy.RUNTIME) public @interface ApplicationScope { }
接下来在GsonModule中使用@ApplicationScope:
@Module public class GsonModule { @ApplicationScope @Provides public Gson provideGson(){ return new Gson(); } }
为了处理多个Activity,咱们建立ActivityComponent,并使用@ApplicationScope,以下所示:
@ApplicationScope @Component(modules = GsonModule.class) public interface ActivityComponent { void inject(MainActivity activity); void inject(SecondActivity activity); }
建立App类继承自Application,用来提供ActivityComponent实例,以下所示:
public class App extends Application { ActivityComponent activityComponent; @Override public void onCreate() { super.onCreate(); activityComponent = DaggerActivityComponent.builder().build(); } public static App get(Context context){ return (App) context.getApplicationContext(); } public ActivityComponent getActivityComponent() { return activityComponent; } }
最后在MainActivity中实现以下代码:
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Inject Gson gson; @Inject Gson gson1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); App.get(this).getActivityComponent().inject(this); Button btnJump = findViewById(R.id.btn_jump); btnJump.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this, SecondActivity.class)); } }); } }
SecondActivity中的代码也是相似的,运行程序,发现MainActivity和SecondActivity的Gson的内存地址是同样的。
@Component也能够用dependencies依赖于其余Component。咱们从新建立一个Swordsman类:
public class Swordsman { @Inject public Swordsman() { } public String fighting(){ return "真是麻烦呀!"; } }
接下来,按照惯例建立SwordsmanModule和SwordsmanComponent,以下所示:
@Module public class SwordsmanModule { @Provides public Swordsman providerSwordsman(){ return new Swordsman(); } } @Component(modules = SwordsmanModule.class) public interface SwordsmanComponent { Swordsman getSwordsman(); }
随后在此前定义的App中引入SwordsmanComponent,以下所示:
public class App extends Application { ActivityComponent activityComponent; @Override public void onCreate() { super.onCreate(); activityComponent = DaggerActivityComponent.builder().build(); DaggerSwordsmanComponent.builder().build(); } public static App get(Context context){ return (App) context.getApplicationContext(); } public ActivityComponent getActivityComponent() { return activityComponent; } }
最后咱们在SecondActivity中使用Swordsman,以下所示:
public class SecondActivity extends AppCompatActivity { private static final String TAG = "SecondActivity"; @Inject Swordsman swordsman; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); App.get(this).getActivityComponent().inject(this); String content = swordsman.fighting(); Log.e(TAG, "swordsman:" + content); } }
注意:自定义的全局Application须要在清单文件中定义:
android:name=".App"
Dagger2提供了懒加载模式,在@Inject的时候不初始化,而是使用的时候,调用get方法来获取实例。 接着咱们改写上面提到的Swordsman,将它改写为懒加载模式。
public class SecondActivity extends AppCompatActivity { private static final String TAG = "SecondActivity"; @Inject Lazy<Swordsman> swordsmanLazy; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); App.get(this).getActivityComponent().inject(this); Swordsman swordsman = swordsmanLazy.get(); String content = swordsman.fighting(); Log.e(TAG, "swordsman:" + content); } }