看了网上很多篇关于Dagger2的入门文章,说真的对新手而言很难看懂,由于自己也是刚学习Dagger2,所以这篇文章站在初学者的角度编写完成。
简单依赖
首先,先来看看为引入Dagger2之前,我们是在怎么构造一个对象依赖的。
定义SimpleA、SimpleB对象
public class SimpleA {
private String name;
public SimpleA(){
}
public void print(){
System.out.println("Simple A 被调用了");
}
}
public class SimpleB {
SimpleA simpleA;
public SimpleB(){
}
public SimpleB(SimpleA a){
this.simpleA = a;
}
public SimpleA getSimpleA() {
return simpleA;
}
}
Simple在其它类中被依赖
public class ExSimpleAActivity extends AppCompatActivity {
SimpleA simpleA;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex_simplea_activity);
simpleA = new SimpleA();
}
}
使用dagger2之后
先在需要调用的注入的类(container)中,使用@Inject 代替new SimpleA()
public class ExSimpleAActivity extends AppCompatActivity {
@Inject
SimpleA simpleA;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex_simplea_activity);
simpleA.print();
}
}
将new 对象替换成了@inject
注解,当然这样还是不行的,在Spring中用注解也是需要在bean.xml中配置的对吧,这里也一样。有两种解决方案
方案一:在类中的构造函数上加注解@Inject
public class SimpleA {
private String name;
@Inject // 注意这儿
public SimpleA(){
}
public void print(){
System.out.println("Simple A 被调用了");
}
}
@Component
public interface SimpleAComponent {
SimpleA getSimpleA();
}
public class ExSimpleAActivity extends AppCompatActivity {
@Inject
SimpleA simpleA;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex_simplea_activity);
simpleA = DaggerSimpleAComponent.create().getSimpleA();
simpleA.print();
}
}
方案二:添加一个Module
public class SimpleA {
private String name;
// @Inject 注意这儿可以没有
public SimpleA(){
}
public void print(){
System.out.println("Simple A 被调用了");
}
}
@Module
public class SimpleAModule {
@Provides
SimpleA providerSimpleA(){
return new SimpleA();
}
}
@Component(modules = SimpleAModule.class) // 注意传入的是Module
public interface SimpleAComponent {
// SimpleA getSimpleA();
void injectSimpleAActivity(ExSimpleAActivity simpleAActivity);
}
public class ExSimpleAActivity extends AppCompatActivity {
@Inject
SimpleA simpleA;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex_simplea_activity);
DaggerSimpleAComponent.create().injectSimpleAActivity(this);
simpleA.print();
}
}
这部分表示了一个类可以通过在构造方法上加注解@Inject或在Module中提供实例的方式来注入到另一个类中,并通过对应的Dagger**Component来获取。第二种方案主要用于引入第三方库时无法修改源代码,故需要在Module中提供实例。
多层依赖
当需要依赖SimpleB的时候,它可能又依赖SimpleA,在以前的代码中就是下面这样
public class MainActivity extends AppCompatActivity {
...
SimpleA a = new SimpleA();
SimpleB b = new SimpleB(a)
...
}
所以这时候在A Module中也需要提供B 的实例。也有两种方案:
方案一:如果已经有定义了依赖SimpleA的Module直接include即可,没有则也需要在这里提供
@Module(includes = SimpleAModule.class)
public class SimpleBModule {
@Provides
public SimpleB provideSimpleB(SimpleA a){
return new SimpleB(a);
}
// 如果没有提供SimpleA()的module
// @Provides
// public SimpleA providerSimpleA(){
// return new SimpleA();
// }
}
对应Activity
public class ExSimpleActivity extends AppCompatActivity {
@Inject
SimpleA simpleA;
@Inject
SimpleB simpleB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex_simple_activity);
DaggerSimpleComponent.builder()
.simpleAModule(new SimpleAModule())
.simpleBModule(new SimpleBModule())
.build()
.injectSimpleACtivity(this);
// DaggerSimpleComponent.create().injectSimpleACtivity(this);
Log.v("simpleA", String.valueOf(simpleA.hashCode()));
Log.v("simpleB", String.valueOf(simpleB.hashCode()));
Log.v("simpleB.A", String.valueOf(simpleB.getSimpleA().hashCode()));
}
}
这里插一句,会发现DaggerSimpleComponent
的写法怎么不一样的,其实create方法中的实现就是builder,所以两种是一样的。同时,如果需要依赖两个类的话,在component中需要加载他们的module。
@Component(modules = {SimpleAModule.class, SimpleBModule.class})
public interface SimpleComponent {
void injectSimpleACtivity(ExSimpleActivity simpleActivity);
}
方案二
@Module
public class SimpleBModule {
public SimpleA simpleA;
public SimpleBModule(SimpleA A){ // 构造传参
this.simpleA = A;
}
@Provides
public SimpleB provideSimpleB(){
return new SimpleB(simpleA);
}
}
public class ExSimpleActivity extends AppCompatActivity {
@Inject
SimpleA simpleA;
@Inject
SimpleB simpleB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex_simple_activity);
DaggerSimpleComponent.builder()
.simpleAModule(new SimpleAModule())
.simpleBModule(new SimpleBModule(simpleA))
.build()
.injectSimpleACtivity(this);
// DaggerSimpleComponent.create().injectSimpleACtivity(this);
Log.v("simpleA", String.valueOf(simpleA.hashCode()));
Log.v("simpleB", String.valueOf(simpleB.hashCode()));
Log.v("simpleB.A", String.valueOf(simpleB.getSimpleA().hashCode()));
}
}
Singleton问题
局部单例
通过打印它们的hashcode发现即使在SimpleBModule中include了SimpleAModule,但还是产生了两个SimpleA
修改下SimpleBModule、SimpleAModule。由于我们的目的是B中的A是要成为单例的,所以将SimpleAModule注解为Singleton即可,注意@Module上不要加!
@Module
public class SimpleAModule {
@Singleton
@Provides
public SimpleA providerSimpleA(){
return new SimpleA();
}
}
@Module(includes = SimpleAModule.class)
public class SimpleBModule {
@Provides
public SimpleB provideSimpleB(SimpleA a){
return new SimpleB(a);
}
}
在对应component中也需要添加上@Singleton
@Singleton
@Component(modules = {SimpleAModule.class, SimpleBModule.class})
public interface SimpleComponent {
void injectSimpleACtivity(ExSimpleActivity simpleActivity);
}
可以看到,传入B的A也是同一个对象。这是因为B中的A本质上也是由SimpleAModule提供的。
那局部单例和全局单例又是怎么回事呢?我们创建一个新的活动来看看。
在SimpleAComponent注入两个活动,分别在两个活动中@Inject一个SimpleA实例,启动活动A的时候跳转到活动B,打印出各自SimpleA的hashcode
@Singleton
@Component(modules = SimpleAModule.class)
public interface SimpleAComponent {
// SimpleA getSimpleA();
void injectSimpleAActivity(ExSimpleAActivity simpleAActivity);
void injectSimpleAActivity(ExSimpleBActivity simpleBActivity);
}
可以看到,两个活动中的SimpleA不一样(一个活动中多次Inject是一样的)。那么这就是局部单例,当Component中注入了不同的类,他们产生的实例也不相同
全局单例
那么如何做到全局单例?
先来看看SimpleBActivity中的代码,create是可以用Builder替代的,也就是说在这个类中其实会生成一个SimpleAComponent对象,然后再注入。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex_simpleb_activity);
DaggerSimpleAComponent.create().injectSimpleBActivity(this);
//SimpleAComponent build = DaggerSimpleAComponent.builder().simpleAModule(new SimpleAModule()).build();
//build.injectSimpleBActivity(this);
Log.v("simpleA 1", String.valueOf(a1.hashCode()));
}
所以由于Component在两个activity中被各自被实例化一次,,导致产生了两个不同的对象,所以我们需要做到让Component能够实现单例。Android中,我们知道在整个App生命周期中都只有一个Appclication实例,所以在Application中获得一个唯一的component实例,用它来提供我们需要的单例。
新建一个MyApplication
public class MyApplication extends Application {
private SimpleAComponent singleSimpleAComponent;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
singleSimpleAComponent = DaggerSimpleAComponent.builder()
.simpleAModule(new SimpleAModule())
.build();
}
public SimpleAComponent getSingleSimpleAComponent(){
return singleSimpleAComponent;
}
}
修改A、B两个活动的代码,Component从Application中获取。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex_simplea_activity);
// DaggerSimpleAComponent.create().injectSimpleAActivity(this);
SimpleAComponent singleSimpleAComponent = ((MyApplication) getApplication()).getSingleSimpleAComponent();
singleSimpleAComponent.injectSimpleAActivity(this);
Log.v("simpleA", String.valueOf(simpleA.hashCode()));
Intent intent = new Intent(this, ExSimpleBActivity.class);
startActivity(intent);
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex_simpleb_activity);
// DaggerSimpleAComponent.create().injectSimpleBActivity(this);
//SimpleAComponent build = DaggerSimpleAComponent.builder().simpleAModule(new SimpleAModule()).build();
//build.injectSimpleBActivity(this);
SimpleAComponent singleSimpleAComponent = ((MyApplication) getApplication()).getSingleSimpleAComponent();
singleSimpleAComponent.injectSimpleBActivity(this);
Log.v("simpleA 1", String.valueOf(a1.hashCode()));
}
这时候句可以看到全局单例了
区分@Provides 方法
当有Context需要注入时,Dagger2就会在Module中查找返回类型为Context的方法。但是,当Container需要依赖两种不同的Context时,你就需要写两个@Provides方法,而且这两个@Provides方法都是返回Context类型,靠判别返回值的做法就行不通了。这就可以使用@Named注解来区分
//定义Module
@Module
public class ActivityModule{
private Context mContext ;
private Context mAppContext = App.getAppContext(); // 另一种Context
public ActivityModule(Context context) {
mContext = context; // 通过传参来构造
}
@Named("Activity") //@ContextLife("Activity")
@Provides
public Context provideContext(){
return mContext;
}
@Named("Application") //@ContextLife ("Application")
@Provides
public Context provideApplicationContext (){
return mAppContext;
}
}
//定义Component
@Component(modules={ActivityModule.class})
interface ActivityComponent{
void inject(Container container);
}
//定义Container
class Container extends Fragment{
@Named("Activity") //@ContextLife("Activity")
@Inject
Context mContext;
@Named("Application") //@ContextLife ("Application")
@Inject
Context mAppContext;
...
public void init(){
DaggerActivityComponent.
.activityModule(new ActivityModule(getActivity()))
.inject(this);
}
}