概述
Dagger2 是一款使用在Java和Android上的依赖注入的一个类库。
使用
配置环境
在module的gradle文件中做如下配置
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'me.tatarka.retrolambda'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
apt 'com.google.dagger:dagger-compiler:2.4'
compile 'com.google.dagger:dagger:2.4'
provided 'org.glassfish:javax.annotation:10.0-b28'
然后在最外层的gradle中配置
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'me.tatarka:gradle-retrolambda:3.2.4'
环境配置好了,我们来写代码
代码
用法一
先看一个简单的使用
public class Poetry {
private String mPoem;
@Inject // 用Inject标记构造函数,表示用它来注入到目标对象中去
public Poetry(){
mPoem = "生活像海洋";
}
public Poetry(String content){
mPoem = content;
}
public String getmPoem(){
return mPoem;
}
}
然后需要创建一个连接器,
@Component //用@Component表示这个接口是一个连接器,能用@Component注解的只
//能是interface或者抽象类
public interface MainActivityComponent {
/**
* 需要用到这个连接器的对象,就是这个对象里面有需要注入的属性
* (被标记为@Inject的属性)
* 这里inject表示注入的意思,这个方法名可以随意更改,但建议就
* 用inject即可。
*/
void inject(MainActivity activity);
}
最后我们在MainActivity中这样写
public class MainActivity extends AppCompatActivity {
private TextView textView;
@Inject //添加@Inject注解,表示这个mPoetry是需要注入的
Poetry mpoery;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
// 使用Dagger2生成的类 生成组件进行构造,并注入
DaggerMainActivityComponent.builder().build().inject(this);
String str = mpoery.getmPoem();
textView.setText( str);
}
}
注意事项:
Inject标签注解的对象不能是private修饰的
Provides标签必须放在Module之中
在多个地方调用同一个连接器对同一个对象进行注解,会生成这个对象的多个实例,如果不想生成,可以使用@Scope标签。
@Scope的作用:标记当前生成实例的使用范围,标识一个类型的注射器只实例化一次,可以实现单例的效果
用法二
@Component(modules = ActivityModule.class)
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
public class UserModel {
public String name;
public int age;
//只能够使用一个Inject
public UserModel(String name,int age){
this.name = name;
this.age = age;
}
@Inject
public UserModel(){
}
}
@Module
public class ActivityModule {
@Provides
public UserModel provideUserModel(){
return new UserModel("小明",22);
}
}
public class MainActivity extends AppCompatActivity {
@Inject
UserModel userModel;
private MainActivityComponent mainActivityComponent;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
//使用Module方式
// mainActivityComponent = DaggerMainActivityComponent.builder().activityModule(new ActivityModule()).build();
// mainActivityComponent.inject(this);
//不使用module
DaggerMainActivityComponent.builder().build().inject(this);
textView.setText(userModel.toString());
}
}
用法三
public class DemoApplication extends Application {
@Inject
LocationManager locationManager;//不能使用private修饰
ApplicationComponent applicationComponent;
private DemoApplication application;
@Override
public void onCreate() {
super.onCreate();
applicationComponent = DaggerApplicationComponent.builder().androidModule(new AndroidModule(this)).build();
applicationComponent.inject(this);
application = this;
}
public ApplicationComponent component(){
return applicationComponent;
}
}
@Component(modules = AndroidModule.class)
public interface ApplicationComponent {
void inject(DemoApplication application);
}
@Module
public class AndroidModule {
public DemoApplication application;
public AndroidModule(DemoApplication application){
this.application = application;
}
@Provides//提供context对象
Context provideApplicationContext(){
return application;
}
@Provides//提供locationmanager
public LocationManager getLocationManager(){
return (LocationManager) application.getSystemService(Context.LOCATION_SERVICE);
}
}
用法四(带有参数的构造方法)
public class UserModel {
public String name;
public int age;
private Context mContext;
//只能够使用一个Inject
public UserModel(String name,int age){
this.name = name;
this.age = age;
}
@Inject
//参数必须在module中标记出来
public UserModel(Context context){
mContext = context;
}
}
@Module
public class AndroidModule {
public DemoApplication application;
public AndroidModule(DemoApplication application){
this.application = application;
}
@Provides//提供context对象,作为UserModel的构造函数的参数
Context provideApplicationContext(){
return application;
}
@Provides//提供locationmanager
public LocationManager getLocationManager(){
return (LocationManager) application.getSystemService(Context.LOCATION_SERVICE);
}
}
public class MainActivity extends AppCompatActivity {
@Inject
UserModel userModel;
private MainActivityComponent mainActivityComponent;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
MainActivityComponent activityComponent = DaggerMainActivityComponent.builder().androidModule
(new AndroidModule((DemoApplication) getApplication())).build();
activityComponent.inject(this);
textView.setText(userModel.toString());
}
用法五(单例)
要实现单例我们用@Singleton注解,这里有两个地方需要注意:
1.首先给我们的实体加上此注解
@Singleton
public class UserModel {
public String name;
public int age;
private Context mContext;
//只能够使用一个Inject
public UserModel(String name,int age){
this.name = name;
this.age = age;
}
@Inject
//参数必须在module中标记出来
public UserModel(Context context){
mContext = context;
}
}
2.给容器也加上此注解
@Singleton
@Component(modules = AndroidModule.class)
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
只有实现了上面两部,才能实现单例
public class MainActivity extends AppCompatActivity {
@Inject
UserModel userModel;
@Inject
UserModel userModel2;
private MainActivityComponent mainActivityComponent;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
mainActivityComponent = DaggerMainActivityComponent.builder().androidModule(new AndroidModule((DemoApplication) getApplication())).build();
mainActivityComponent.inject(this);
textView.setText(userModel.toString()+"\n"+userModel2.toString());
}
}
此时我们的两个对象的地址就是同一个了。
如果不给实体加@Singleton注解,无法实现单例,如果只给实体加注解而不给容器加注解,运行时会出现如下的错误
用法六(单例)
我们用另一种方式实现单例,这种方式不需要在实体上注解,我们放到Module中
@Module
public class AndroidModule {
public DemoApplication application;
public AndroidModule(DemoApplication application){
this.application = application;
}
@Provides//提供context对象,作为UserModel的构造函数的参数
Context provideApplicationContext(){
return application;
}
@Provides//提供locationmanager
public LocationManager getLocationManager(){
return (LocationManager) application.getSystemService(Context.LOCATION_SERVICE);
}
@Singleton
@Provides
public UserModel provideUserModel(){
return new UserModel(application);
}
}
MainActivityComponent 同样需要注解
@Singleton
@Component(modules = AndroidModule.class)
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
用法七(依赖其他组件)
@Module
public class AndroidModule {
public DemoApplication application;
private LocationManager locationManager;
public AndroidModule(DemoApplication application){
this.application = application;
locationManager = (LocationManager) application.getSystemService(Context.LOCATION_SERVICE);;
}
@Singleton
@Provides//提供context对象,作为UserModel的构造函数的参数
Context provideApplicationContext(){
return application;
}
@Singleton
@Provides//提供locationmanager
public LocationManager getLocationManager(){
return locationManager;
}
}
@Singleton
@Component(modules = AndroidModule.class)
public interface ApplicationComponent {
//注入到DemoApplication中
void inject(DemoApplication application);
LocationManager getLocationManager();//子组件需要Application中的某个实例的时候,需要提供这个接口
}
@PerActivity//如果对应的modules里面有@Scope注解,那么容器里也必须加上,此处为@PerActivity
//依赖ApplicationComponent
@Component(dependencies = ApplicationComponent.class,modules = ActivityModule.class)
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
这里我们自定义了一个注解@PerActivity
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {
}
@Module
public class ActivityModule {
private Context mContext;
public ActivityModule(Context context){
mContext = context;
}
@PerActivity
@Provides//必须提供Context对象,否则会报错
public Context provideContext(){
return mContext;
}
}
接下来就是使用了,我们先在DemoApplication里面注解,
public class DemoApplication extends Application {
@Inject
LocationManager locationManager;//不能使用private修饰
ApplicationComponent applicationComponent;
private DemoApplication application;
@Override
public void onCreate() {
super.onCreate();
applicationComponent = DaggerApplicationComponent.builder().androidModule(new AndroidModule(this)).build();
applicationComponent.inject(this);
application = this;
}
public ApplicationComponent getComPonent(){
return applicationComponent;
}
}
然后在MainActivity里面依赖
mainActivityComponent = DaggerMainActivityComponent.builder().activityModule(new ActivityModule(this))
.applicationComponent(((DemoApplication) getApplication()).getComPonent()).build();
mainActivityComponent.inject(this);
使用八(Qualifier)
通过自定义Qulifier,可以告诉Dagger2去需找具体的依赖提供者
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ForBoy {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ForGirl {
}
然后在Module中我们这样写
@ForBoy//根据不同注释,返回不同对象
@Provides
UserModel provideBoy(){
return new UserModel("boy");
}
@ForGirl
@Provides
UserModel provideGirl(){
return new UserModel("girl");
}
具体使用
public class MainActivity extends AppCompatActivity {
@ForBoy
@Inject
UserModel boy;
@ForGirl
@Inject //接收Inject或者Providers
UserModel girl;
private MainActivityComponent mainActivityComponent;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
mainActivityComponent = DaggerMainActivityComponent.builder().activityModule(new ActivityModule(this))
.applicationComponent(((DemoApplication) getApplication()).getComPonent()).build();
mainActivityComponent.inject(this);
textView.setText(boy.name+"\n"+girl.name);
}
}