您的位置:首页 > 其它

Dagger2从0基础使用,到单例注入的正确姿势

2017-03-31 10:28 351 查看

Dagger2从0基础使用,到单例注入的正确姿势

环境搭建

基本流程

四个基础注解 @Inject @Module @Provides @Component

实现单例的两种注入方式

一、环境搭建

1、工程的gradle文件配置

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}


2、module的gradle文件配置

apply plugin: 'com.neenbedankt.android-apt'

dependencies {

compile 'com.google.dagger:dagger:2.7'
apt 'com.google.dagger:dagger-compiler:2.7'

}


二、 基本流程

Dagger2使用编译时注解apt,通过apt,通过生成工具类将注入的需求者和注入的提供者联系起来,在我们需要给注入的需求者注入的地方,调用生成的工具类,传入注入的需求者,工具类自己就可以去查找提供者来进行注入。

借图一张(http://www.jianshu.com/p/c556b415b800



三、四个基础注解

1、 @Inject (标记属性或者构造函数)

作用1:在类中给属性标记注解,表明这个属性需要Dagger2来给我注入

作用2:在构造函数上面标记注解,表明这个构造函数是注入的提供者,可以提供该对象的注入

2、 @Module(标记类)

作用:说明该类是一个注入的提供者类

3、 @Provides(标记方法)

作用:说明该方法是注入的提供者,方法的返回值就是提供的注入的对象

4、 @Component(标记类)

作用:将注入的需求者和提供者联系起来

先来实现一个最简单的注入:

第一个类SimpleObj 注入提供者

public class SimpleObj {
public String objName;
@Inject//构造函数有这个注解
public SimpleObj(){
objName = "名字来源于注入";
}
}


第二个类,注入的需求者,不能用private修饰

public class MainActivity extends AppCompatActivity {
@Inject
SimpleObj simpleObj;//属性被Inject注解标记,
@Override
protected void onResume() {
super.onResume();
Log.i("aaa",simpleObj.objName);//没有实例化simpleObj 直接输出

}


这个时候运行肯定崩溃,我们自己还没有注入呢。

第三个类 注入的入口,也就是联系人

/**
* Created by limengjie
* on 2017/3/30.17:30
*/
@Component()//这个标记必须
public interface SimpleComponent {
void inject(MainActivity m);//这个方法必须
}


在联系人这里,我们只看到了注入需求者,没有看到提供者,这是因为没有系统会自动去查找的,多有的注入者Dagger2都是知道的,这里先不去关心这个问题。

第四个步骤,rebulid一下

如果成功,会在app\build\generated\source\apt 目录下面生成一些文件,其中就有需求提供者的身影,最重要的联系人SimpleComponent,变成了DaggerSimpleComponent

第五个步骤,在MainAcitivity中注入

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initInject();
}
public void initInject(){
DaggerSimpleComponent.builder().build();

}


最后运行结果

03-30 09:47:12.686 28281-28281/? I/aaa: 名字来源于注入


如果认真完成了上面的步骤,会觉得注入这么简单,那是因为还有几个注解没用上@Module、 @Singleton和@Component的属性dependencies与modules。

5、@Component的属性dependencies与modules。

第一步改造

@Module
public class SimpleObj {
public String objName;
@Inject
public SimpleObj(){
objName = "名字来源于注入";
}
@Provides
public SimpleObj provideSimpleObj(){
return new SimpleObj();
}

}


这样它就可以写到@Component的属性module里面

第二步改造,在component中加入module

@Component(modules = SimpleObj.class)
public interface SimpleComponent {
void inject(MainActivity m);
}


当然会想,我不要这个都可以注入,我要他来何用,且看rebulid后生成的代码

public final class DaggerSimpleComponent implements SimpleComponent {
private MembersInjector<MainActivity> mainActivityMembersInjector;

public static final class Builder {
private SimpleObj simpleObj;

private Builder() {}

public SimpleComponent build() {
if (simpleObj == null) {
this.simpleObj = new SimpleObj();
}
return new DaggerSimpleComponent(this);
}

public Builder simpleObj(SimpleObj simpleObj) {
this.simpleObj = Preconditions.checkNotNull(simpleObj);
return this;
}
}
这里 public Builder simpleObj(SimpleObj simpleObj)方法多出来,也就是这个注入的提供者,我们可以自己传入了

对比以前的:
public static final class Builder {
private Builder() {}

public SimpleComponent build() {
return new DaggerSimpleComponent(this);
}
}

我们在使用的时候
DaggerSimpleComponent.builder().simpleObj(new SimpleObj()).build().inject(this);

这样我们在通过component注入的时候,可以自己传入提供者。


四、实现单例注入

方式一injcet构造函数注入:

1、提供者
@Singleton //这个注解可以换成自己的随便都可以
public class SimpleObj {
public String objName;

@Inject
public SimpleObj(){
objName = "名字来源于注入";
}
//    @PerActivityXX3
//    @Provides
//    public SimpleObj provideSimpleObj(){
//        return new SimpleObj();
//    }

}
2、中间人
@Singleton//这里的注解必须和提供者注解范围一致,可以自定义随便写,但是要一致才可以
@Component()
public interface SimpleComponent {
void inject(MainActivity m);
}

public class MainActivity extends AppCompatActivity {
@Inject
SimpleObj simpleObj;
@Inject
SimpleObj simpleObj2;

private TextView tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
appCompoent = DaggerAppCompoent.builder().jiaMoudle(new JiaMoudle("")).build();
initInject();
}
public void initInject(){
DaggerSimpleComponent.builder().build().inject(this);
}

@Override
protected void onResume() {
super.onResume();
Log.i("aaa",simpleObj.toString());
Log.i("aaa",simpleObj2.toString());

}

输出结果
I/aaa: com.example.administrator.mydagger2demo.injector.SimpleObj@1714c5d
I/aaa: com.example.administrator.mydagger2demo.injector.SimpleObj@1714c5d


现在这整个MainActiviy中实现了单例,要想全局单例,只需要把DaggerSimpleComponent.builder().build()返回的SimpleComponent实例全局单例存起来,就可以,在其他需要注入SimpleObj的地方调用SimpleComponent实例来注入就全局单例了。

方式二、module提供provides注解的方法

1.提供者
@Module
public class SimpleObj {
public String objName;

public SimpleObj(){
objName = "名字来源于注入";
}
@Singleton
@Provides
public SimpleObj provideSimpleObj(){
return new SimpleObj();//每次注入都是new的,单例的话只会调用一次这里,下次回去缓存查找
}
}

2、中间人

@Singleton
@Component(modules = SimpleObj.class) public interface SimpleComponent { void inject(MainActivity m); }3、注入需求者mainactivity不变

public class MainActivity extends AppCompatActivity {
@Inject
SimpleObj simpleObj;
@Inject
SimpleObj simpleObj2;

private TextView tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
appCompoent = DaggerAppCompoent.builder().jiaMoudle(new JiaMoudle("")).build();
initInject();
}
public void initInject(){
DaggerSimpleComponent.builder().build().inject(this);

}

@Override
protected void onResume() {
super.onResume();
Log.i("aaa",simpleObj.toString());
Log.i("aaa",simpleObj2.toString());
}
输出结果,
I/aaa: com.example.administrator.mydagger2demo.injector.SimpleObj@1714c5d
I/aaa: com.example.administrator.mydagger2demo.injector.SimpleObj@1714c5d


注意:

标记只有@Singleton,可以实现单例,但是它的范围只是在compoent的生命周期内,如果你在新bulid一个component,那么他提供注入的实例就不和以前一样了。

全局单例:必须要@Singleton,且compoent也是全局单例存在,这样提供的注入就是全局单例了。

并且,@Singleton这个范围标记可以换成自定义的范围标记,@Singleton只是见名只意罢了,换成其他的范围标记是一样的,Dagger的范围标记提供了compoent声明周期内的单例,具体要扩展到全局单例还是其他的范围,只需要把compoent的声明周期控制就行了。

总结

要想实现全局单例,注入者提供者必须全局单例存在,提供注入的方法必须给定范围,component的范围和moudle方法范围一致,如果是构造函数inject,则这个类必须标记一致的范围。

参考地址http://www.jianshu.com/p/1d42d2e6f4a5
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Dagger2