Daager2-初认识一
Daager2-初认识一
背景:
有什么能比那把黄油刀(butterknife)更加犀利的名字唯有dagger了
最早的版本Dagger1 由Square公司开发。依赖注入框架主要用于模块间解耦,提高代码的健壮性和可维护性。Dagger 这个库的取名不仅仅来自它的本意“匕首”同时也暗示了它的原理
Dagger2 是一个Android依赖注入框架,由谷歌开发,因为主流是Dagger2所以接下来我们直接学习如何使用它
认识依赖注入
说了那么多,那到底依赖注入是什么呢?上代码:
public class MainActivity extends AppCompatActivity { User user; public void setUser(User user) { this.user = user; }
依赖:MainActivity 包含了一个User对象,我们就说MainActivity 依赖于user;
注入:因为user对象是通过传递初始的,不是直接new出的对象,所以这样的方式就叫做注入;
通过上面简单的一小段代码估计大家对依赖注入有了了解,通过依赖注入可以有效的减少我们的耦合,既然这样可以实现依赖注入,为什么还需要dagger这样的第三方库处理呢?
1.增加开发效率、省去重复的简单体力劳动
首先new一个实例的过程是一个重复的简单体力劳动,dagger2完全可以把new一个实例的工作做了,因此我们把主要精力集中在关键业务上、同时也能增加开发效率上。
省去写单例的方法,并且也不需要担心自己写的单例方法是否线程安全,自己写的单例是懒汉模式还是饿汉模式。因为dagger2都可以把这些工作做了。
2.更好的管理类实例
每个app中的ApplicationComponent管理整个app的全局类实例,所有的全局类实例都统一交给ApplicationComponent管理,并且它们的生命周期与app的生命周期一样。
每个页面对应自己的Component,页面Component管理着自己页面所依赖的所有类实例。
因为Component,Module,整个app的类实例结构变的很清晰。
3.解耦
假如不用dagger2的话,一个类的new代码是非常可能充斥在app的多个类中的,假如该类的构造函数发生变化,那这些涉及到的类都得进行修改。设计模式中提倡把容易变化的部分封装起来。
说了那么多概念,估计大家已经对dagger有了一定的了解,那开咱们的使用吧,毕竟实战才是最有用的嘛
使用
还是结合一开始的例子,我们采用dagger的方式看如何给MainActivity 传递一个依赖的user对象
1.加入依赖包
Github-地址
// Add plugin https://bitbucket.org/hvisser/android-aptbuildscript { repositories { mavenCentral() } dependencies { classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' }}// Apply pluginapply plugin: 'com.neenbedankt.android-apt'// Add Dagger dependenciesdependencies { compile 'com.google.dagger:dagger:2.x' apt 'com.google.dagger:dagger-compiler:2.x'}
2.注解方法
- @Inject: 通常在需要依赖的地方使用这个注解。换句话说,你用它告诉Dagger这个类或者字段需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。
- @Module: Modules类里面的方法专门提供依赖,所以我们定义一个类,用 @Module注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到需要的 依赖。modules的一个重要特征是它们设计为分区并组合在一起(比如说,在我们的app中可以有多个组成在一起的modules)。
- @Provides: 在modules中,我们定义的方法是用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。
- @Component: Components从根本上来说就是一个注入器,也可以说是@Inject和@Module的桥梁,它的主要作用就是连接这两个部分。 Components可以提供所有定义了的类型的实例,比如:我们必须用@Component注解一个接口然后列出所有的 @Modules组成该组件,如 果缺失了任何一块都会在编译的时候报错。所有的组件都可以通过它的modules知道依赖的范围。
- @Scope: Scopes可是非常的有用,Dagger2可以通过自定义注解限定注解作用域。后面会演示一个例子,这是一个非常强大的特点,因为就如前面说的一样,没必要让每个对象都去了解如何管理他们的实例
可以粗滤的过一遍,估计看完也是一头雾水,还是投入到实战中去认识吧!
3.初始user对象
和传统方法一样不多讲了,设置一些属性罢了
public class User { private String name; private String sex; private String ads; ******get/set********** }
4.生成对应module对象
module类就是给user初始化并且提供外部调用的类,这里类中我们需要给user初始,并且返回给dagger一个可调用的对象
@Modulepublic class UserModule { @Provides User provideUser(){ return new User("xxxx","SEX","XXX@Gmail.com"); }}
使用@Module标识类型为module,并用@Provides标识提供依赖的方法
5.生成Component对象
有了提供依赖的组件(module),我们还需要将依赖注入到需要的对象中。连接提供依赖和消费依赖对象的组件被称为Injector。Dagger2中我们将这个对象其称为component。UserComponent代码如下
@Component(modules = UserModule.class)public interface UserComponent { void inject(MainActivity mainActivity);}
可以看到,Component是一个使用@Component标识的Java interface。interface的inject方法需要一个消耗依赖的类型对象作为参数:通过 @Component 添加了一个 Module : UserModule,此外还有一个inject方法,其中的参数表示要注入的位置(先打个预防针,Component中的方法还可以起到暴露资源,实现Component中的“继承”的作用)
注意:这里必须是真正消耗依赖的类型MainActivity,而不可以写成其父类,比如Activity。因为Dagger2在编译时生成依赖注入的代码,会到inject方法的参数类型中寻找可以注入的对象,但是实际上这些对象存在于MainActivity,而不是Activity中。如果函数声明参数为Activity,Dagger2会认为没有需要注入的对象。当真正在MainActivity中创建Component实例进行注入时,会直接执行按照Activity作为参数生成的inject方法,导致所有注入都失败。(是的,我是掉进这个坑了。)
6.完成依赖注入
最后,我们需要在MainActivity中构建Injector对象,通过dagger得到我们的user对象
public class MainActivity extends AppCompatActivity { @Inject User user; UserComponent component; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); component= DaggerUserComponent.builder().userModule(new UserModule()).build(); component.inject(this); TextView textView=(TextView)findViewById(R.id.tv); textView.setText("name:"+user.getName()+"\nsex:"+user.getSex()+"\nads:"+user.getAds()); }}
首先,使用@Inject标志被注入的对象User (注意User 不能为private),之后通过Dagger2生成的实现了我们提供的UserComponent 接口类DaggerUserComponent创建component,调用其inject方法完成注入。
至此,我们使用Dagger实现了最简单的依赖注入!
注意:这里的DaggerUserComponent不是我们自己创建的,是dagger自动在build时(可手动make project)创建的,后边的userModule也是更具你在Component设置的module对象生成的方法-如果不成功需先clean工程在make一遍
效果
源码
源码传送门-csdn-戳我
建议
如果你有任何的问题和建议欢迎加入QQ群告诉我!
更多相关文章
- Android(安卓)Handler消息处理机制详解
- Socket 通信原理 -- Android客户端和服务器以TCP&&UDP方式互通
- Android(安卓)进程间通信(IPC)-上
- android中四大引用的区别,强引用、软引用、弱引用和虚引用
- 制作一款简单的网络图片查看器
- Android中AsyncTask使用教程及源码分析
- Android(安卓)进阶:JSON数据与Java对象转换 - Gson的使用与实践
- Android中静态变量的生命周期
- 第三部分:Android(安卓)应用程序接口指南---第三节:应用程序资源--