Dagger从入门到放弃

Dagger的好处:
使用Dagger2 的好处比较明显的就是,可以方便的修改,构建对象。 比如很多对象的构建都需要Context,你只要有一个可以提供Context的moudule就可以了,还可以比较方便的控制对象的生命周期,简单来讲就是可以很方便的构建和修改对象的构造函数(只需要维护好Component,module,当然这些对于新手并不简单)。

Dagger的缺点:
1.移动类到不同的包下,或者重命名某个类之后,需要执行以下步骤:

Build-->Clean Project-->Make Project-->run

如果改动了XComponent类,则要记得在Make Project之后加上最新的DaggerXComponent.create().inject()代码。

2.类的初始化变得隐晦而呆板,比如要使用动态的参数来初始化某个类,比如:

StudentData data = new StudentData(name, sex, age);

上述name, sex, age是动态变化的,此时Dagger就显得手足无措了,或者Dagger的初衷本来就不是应付动态参数实例化的,如果有朋友发现Dagger能轻松应付这种场景的方法,还请多多指教。
3.Module功能局限性太大。在Module里,用@Provide标注的实例化入口,返回类型不能雷同,比如:

@Provides
String provideName() {
	return "张三";
}

@Provides
String provideAddress() {
	return "广东省深圳市";
}

这样写编译是不能通过的,因为你有两个@Provides标注的方法均返回了String这个类型,那么你在其他类Inject的时候,Dagger不知道你想要拿哪一个String,当然,你可以通过增加@Named来区分,这样一来,你在Activity中使用的时候,变量也要加上相应的@Named注解,并指明对应的值,你的注解越来越多。

4.类的急剧增加,维护成本增加。比如,有一个类AppConfigure,它的构造函数不能直接拿到,因为这个类是jar包里提供的,其全局唯一,要在MainActivity里使用,传统的写法,可能是这样的:
① 新建一个单例类,维护这个AppConfigure。
② 在MainActivity里初始化并使用该单例类。
以上,一共才新建了两个类,直接Run就行,简单明了。
但是如果使用Dagger,你可能要这样做:
① 新建一个Module,里面有一个@Provide标注的方法来产生AppConfigure,根据是不是单例增加相应的注解。
② 新建一个Component,用来关联MainActivity和Module
③ Make Project,产生相应的DaggerComponent类
④ 在MainActivity的onCreate()方法里调用DaggerComponent的方法完成注入
以上是最简单的Dagger使用流程,这样就凭空多了一个Component类。如果你使用的是谷歌官方DaggerAndroid规范,则步骤更多:

Application --> AppComponent 
							--> MainActivityModule --> MainActivitySubComponent --> MainActivitySubModule --> AppConfigure, 其他实体...
																							↑
																						MainActivity
							
							
							--> XXXXActivityModule --> XXXXActivitySubComponent --> XXXXActivitySubModule ...
																							↑
																						XXXXActivity

看到这些,我只想说,丢雷楼某。
5.各种注解相互混搭,可读性极差。我们都知道,注解的使用会让代码显得简洁,但同时忽略了很多细节,特别是对于刚接手别人项目的新同事,瞬间懵逼,这东西到底是干嘛用的。

6.各种小坑,比如注解不能应用在private修饰的变量上,@Provides只能标注public的方法等,编译错误信息太笼统,查找出错的地方相当困难。

7.稍微总结一下吧。有人说,假设有一个3000行的构造方法,参数的类型和个数在版本迭代的时候会经常发生更改,使用Dagger的话,只需要在Module里修改就可以了。但其实我们冷静地想一下,这种“更改”不也是“固定”的吗?因为你更改的那些参数,使用的值都是固定的,那我用一个单例不也一样能搞定吗?有人说,如果要在多个地方使用不同的实例呢?那我一样可以使用建造者模式来实现啊。所以说,不要为了框架的存在而强行使用框架,而要为了项目的整体效率而考虑框架。

注意事项:
注意:
1.假设在XActivity中Inject某个类A,那么在类A中则也拥有XActivity的实例,这个实例是相同的。要想得到这个实例,只需在类A的@Inject标记的构造方法的参数里加上即可,例如:

public class A {
	@Inject
	public A(XActivity activity) {
		...
	}
}

2.在普通的类里,构造函数先被执行完毕,@Inject标记的成员才开始实例化

3.成员初始化的顺序和变量@Inject的顺序有关,比如:

public class XActivity {
	@Inject
	Student student;
	@Inject
	MainPresenter mainPresenter;
	
	...
}

那么student会比mainPresenter先完成实例化。

猜你喜欢

转载自blog.csdn.net/ithouse/article/details/80463648