Android 之dragger使用
1、依赖的注入和配置独立于组件之外,注入的对象在一个独立、不耦合的地方初始化,这样在改变注入对象时,我们只需要修改对象的实现方法,而不用大改代码库。
2、依赖可以注入到一个组件中:我们可以注入这些依赖的模拟实现,这样使得测试更加简单。
3、app中的组件不需要知道有关实例创建和生命周期的任何事情,这些由我们的依赖注入框架管理的。
我觉得,dagger2这样的依赖注入框架对MVP架构来说,是最好的解耦工具,可以进一步降低modle-view-presenter之间的耦合度。
所以,如果你的项目在使用MVP架构开发,强烈建议配合dagger2一起使用。
接下来,在贴代码之前,我先说说明下我的MVP架构和传统的MVP有些不同,传统MVP的M层处理业务逻辑,P层仅仅是V和M的桥梁;而我的P层同时处理与model相关的业务逻辑,不处理View层次的逻辑,View层次的逻辑交给V自己处理,M层仅仅是bean,这种方式是根据开发中的实际情况而作的考虑,这里先不作讨论。
先看结构图:
接下来,分解这张图:
AppComponent: 生命周期跟Application一样的组件。可注入到自定义的Application类中,@Singletion代表各个注入对象为单例。
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
Context context(); // 提供Applicaiton的Context
ThreadExecutor threadExecutor(); // 线程池
ApiService apiService(); // 所有Api请求的管理类
SpfManager spfManager(); // SharedPreference管理类
DBManager dbManager(); // 数据库管理类
}
AppModule: 这里提供了AppComponent里的需要注入的对象。
@Module
public class AppModule {
private final MyApplication application;
public AppModule(MyApplication application) {
this.application = application;
}
@Provides
@Singleton
Context provideApplicationContext() {
return application;
}
@Provides
@Singleton
ThreadExecutor provideThreadExecutor(JobExecutor jobExecutor) {
return jobExecutor;
}
@Provides
@Singleton
ApiService providesApiService(RetrofitManager retrofitManager) {
return retrofitManager.getService();
}
@Provides
@Singleton
SpfManager provideSpfManager() {
return new SpfManager(application);
}
@Provides
@Singleton
DBManager provideDBManager() {
return new DBManager(application);
}
}
这里细心的童鞋可能发现,为何有些方法直接返回入参,有些需要返回一个new的对象呢?
这里如果对DBManager的写法换成:
DBManager provideDBManager(DBManager dbManager) {
return dbManager;
}
这样编译不会通过,会报一个循环依赖的错误,这种写法需要在返回参数和入参不是同一个类的情况下才可以。感兴趣的可以查看dagger2生成的代码。
对于直接返回的类JobExecutor、RetrofitManager,它们类的构造函数一定要加上@Inject的注解:
@Inject
public JobExecutor() {
// 初始化
// ......
}
接下来谈谈ActivityComponent,可以看到有个@ActivityScope注解,这个注解是自定义的,对应Activity的生命周期,Dagger2可以通过自定义注解限定注解作用域,一般在Module里规定scope的生命周期,比如下面的ActivityScope在ActivityModule里绑定。
@Scope
@Retention(RUNTIME)
public @interface ActivityScope {}
ActivityComponent:生命周期跟Activity一样的组件,这里提供了inject方法将Activity注入到ActivityComponent中,通过该方法,将Activity中需要注入的对象注入到该Activity中。
@ActivityScope
@Component(dependencies = AppComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
Activity activity();
void inject(LoginActivity loginActivity);
void inject(MainActivity mainActivity);
// ....
}
ActivityModule:注入Activity,同时规定Activity所对应的域是@ActivityScope
@Module
public class ActivityModule {
private final Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
@Provides
@ActivityScope
Activity activity() {
return this.activity;
}
}
至此,注入工作初步完毕了,看到这里,可能有童鞋有疑问,Presenter(或者Biz)的注入在哪里,为何没在ActivityComponent里?
是的,正常来说,结构图应该是下面这张图的样子:
我建议使用这种方式,对于不同的Activity,创建各个对应的ActivityCompontent,同时把Presenter(Biz)注入到Component的视图中,这也是dagger2推荐的做法,Dagger 2希望使用@Component注解接口将依赖关系链接起来。
而我的做法没有把Presenter注入到ActivityComponent中,因为Presenter的作用域和Activity一样,好处是节省代码(- -),大家可以自行选择注入方式。
使用:
public class LoginActivity extends BaseActivity implements LoginView, ValidCodeView {
@Inject LoginPresenter loginPresenter;
@Inject ValidCodePresenter validCodePresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initInject();
// 此处省略N行代码
}
private void initInject() {
// 构建Component并注入
getActivityComponent().inject(this);
loginPresenter.attachView(this);
validCodePresenter.attachView(this);
}
// 建议写在基类Activity里
protect ActivityComponent getActivityComponent(){
return DaggerActivityComponent.builder()
.appComponent(getAppComponent())
.activityModule(getActivityModule())
.build();
}
// 建议写在基类Activity里
protect ActivityModule getActivityModule(){
return new ActivityModule(this);
}
// 建议写在MyApplication类里
public AppComponent getAppComponent(){
return DaggerAppComponent.builder()
.appModule(new AppModule((MyApplication)getApplicationContext()))
.build();
}
}
其中LoginPresenter:
@ActivityScope
public class LoginPresenter extends DefaultMvpPresenter<LoginView, RESTResult<UserVO>> {
// 此处省略
@Inject
public LoginPresenter(ApiService apiService, ThreadExecutor jobExecutor, SpfManager spfManager) {
this.apiService = apiService;
this.jobExecutor = jobExecutor;
this.spfManager = spfManager;
}
public void login(String mobile, String code) {
// todo
}
}
这样,dagger2的简单使用就介绍完毕了,如果有对一些基础概念不是很理解的童鞋,可以查看官方文档。
原文链接:http://www.jianshu.com/p/c2feb21064bb
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
Android 之dragger使用的更多相关文章
- android UI库
https://github.com/wasabeef/awesome-android-ui List of Android UI/UX Libraries A curated list of awe ...
- Android中GridView拖拽的效果【android进化三十六】
最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的 ...
- Android 一步一步教你使用ViewDragHelper
在自定义viewgroup的时候 要重写onInterceptTouchEvent和onTouchEvent 这2个方法 是非常麻烦的事情,好在谷歌后来 推出了ViewDragHelper这个类.可以 ...
- Android好用且常用的插件及工具
1.GitHub,这个不管是做安卓还是其他,只要是开发就必上的网站,也是天朝没有墙掉为数不多的网站 2.Stack OverFlow,这个和上面一样,国外非常著名的问答网站,在上面基本上很多问题都可以 ...
- Android中GridView拖拽的效果
最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的那么 ...
- android ListView和GridView拖拽移位具体实现及拓展
关于ListView拖拽移动位置,想必大家并不陌生,比较不错的软件都用到如此功能了.如:搜狐,网易,百度等,但是相比来说还是百度的用户体验较好,不偏心了,下面看几个示例: 首 ...
- Dragger代码实现
转自:http://www.apkbus.com/blog-705730-60436.html 在工程中引入Dagger 如果想使用Dagger的话,需要添加两个函数库: dependencies { ...
- android ListView和GridView拖拽移位实现代码
关于ListView拖拽移动位置,想必大家并不陌生,比较不错的软件都用到如此功能了.如:搜狐,网易,百度等,但是相比来说还是百度的用户体验较好,不偏心了,下面看几个示例: 首先 ...
- Android Annotations(2)
AndroidAnnotations是一个开源框架,旨在加快Android开发的效率.通过使用它开放出来的注解api,你几乎可以使用在任何地方, 大大的减少了无关痛痒的代码量,让开发者能够抽身其外,有 ...
随机推荐
- CountDownLatch使用
分享牛原创,CountDownLatch类的使用,CountDownLatch是一个工具类,运行主线程开启子线程的时候,子线程还没有结束的时候,主线程可以一直等待,直到初始化的现成的计数器count为 ...
- Thread Pools
许多程序会动态创建数十个设置上百个线程.举个例子,一个web服务器可能在每一个新到来的请求时创建一个新线程,然后在请求完成后将其终止. 然而,创建一个新线程将会带来一定的耗费:它需要在内核中创建自身必 ...
- Android动态加载入坑指南
曾几何时,国内各大公司掀起了一股研究Android动态加载的技术,两年多过去了,动态加载技术俨然成了Android开发中必须掌握的技术.那么动态加载技术是什么呢,这里谈谈我的个人看法,如有雷同,纯属偶 ...
- Django 表单校验 表单字段设置 自定义表单校验规则
今天看到了一篇非常好的博文,拿来和大家分享一下. 内容包括了: 用户注册时输入数据的校验 使用widget进行字段设置 实现自定义的校验规则 参考自下面的这篇文章
- 【移动开发】plurals
不同的语言对数量的语法规定有不同的规则.在英语里面,例如,1是特例.我们会直接写1book,而针对一个以上的我们会在book后加复数形式.这种区别对单数和复数来说是很普遍的,但是其他的语言做了更好的区 ...
- antlr v4 使用指南连载5——如何编写词法定义
如何编写词法定义 继上一篇文章,相信大家都明了编写词法规则的两个基本原则.那么接下来就可以开始编写词法文件了.对于计算机科学来说,很多词法规则是一致的.如标识符.数字等,它们都可以重复在 ...
- OpenMP基础----以图像处理中的问题为例
OpenMP2.5规范中,对于可以多线程执行的循环有如下5点约束: 1.循环语句中的循环变量必须是有符号整形,如果是无符号整形就无法使用,OpenMP3.0中取消了这个约束 2.循环语句中的比 ...
- SSH深度历险(六) 深入浅出----- Spring事务配置的五种方式
这对时间在学习SSH中Spring架构,Spring的事务配置做了详细总结,在此之间对Spring的事务配置只是停留在听说的阶段,总结一下,整体把控,通过这次的学习发觉Spring的事务配置只要把思路 ...
- UNIX网络编程——UDP 中的外出接口的确定
已连接UDP套接字还可用来确定用于特定目的地的外出接口.这是由connect函数应用到UDP套接字时的一个副作用造成的:内核选择本地IP地址.这个本地IP地址通过为目的IP地址搜索路由表得到外出接口, ...
- Docker教程:dokcer的配置和命令
http://blog.csdn.net/pipisorry/article/details/50803028 Docker命令查询 终端运行docker命令,它会打印所有可用的命令列表及使用描述:# ...