Presention层:
 
整个应用启动的时候,就执行依赖的初始化。编译项目之后,Dagger依赖框架使用ApplicationComponent生成一个DaggerApplicationCOmponent。
 
1. 首先进行依赖的生成
在Application中,调用initializeInjector()就会促使Dagger框架进行依赖生成。
 
ApplicationComponent
对其它Component提供Context,ThreadExecutor,PostExecutionThread,UserRepository依赖
/**
* A component whose lifetime is the life of the application.
*/
@Singleton // Constraints this component to one-per-application or unscoped bindings.
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
void inject(BaseActivity baseActivity); //Exposed to sub-graphs.
Context context();
ThreadExecutor threadExecutor();
PostExecutionThread postExecutionThread();
UserRepository userRepository();
}
ApplicationModule
/**
* Dagger module that provides objects which will live during the application lifecycle.
*/
@Module
public class ApplicationModule {
private final AndroidApplication application; public ApplicationModule(AndroidApplication application) {
this.application = application;
} @Provides @Singleton Context provideApplicationContext() {
return this.application;
} @Provides @Singleton Navigator provideNavigator() {
return new Navigator();
} @Provides @Singleton ThreadExecutor provideThreadExecutor(JobExecutor jobExecutor) {
return jobExecutor;
} @Provides @Singleton PostExecutionThread providePostExecutionThread(UIThread uiThread) {
return uiThread;
} @Provides @Singleton UserCache provideUserCache(UserCacheImpl userCache) {
return userCache;
} @Provides @Singleton UserRepository provideUserRepository(UserDataRepository userDataRepository) {
return userDataRepository;
}
}
在这个类中,提供了生成依赖的方法。
需要参数的provide方法,参数也是通过Dagger依赖框架生成的。
参数JobExecutor(data模块),UIThread(presentation模块),UserCacheImpl(data模块),UserDataRepository(data模块)生成的方式,是Dagger依赖框架调用相应类的构造方法实现的,而不是通过provide实现的。
比如
JobExecutor(data模块):
public class JobExecutor implements ThreadExecutor {
  @Inject
  public JobExecutor() {
    this.workQueue = new LinkedBlockingQueue<>();
    this.threadFactory = new JobThreadFactory();
    this.threadPoolExecutor = new ThreadPoolExecutor(INITIAL_POOL_SIZE, MAX_POOL_SIZE,
        KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, this.workQueue, this.threadFactory);
  }
...
}
属于data模块的:参数JobExecutor(data模块),UserCacheImpl(data模块),UserDataRepository(data模块)
 
Application:
/**
* Android Main Application
*/
public class AndroidApplication extends Application { private ApplicationComponent applicationComponent; @Override public void onCreate() {
super.onCreate();
this.initializeInjector();
} private void initializeInjector() {
this.applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
} public ApplicationComponent getApplicationComponent() { return this.applicationComponent;
}
}
2.MainActivity实现
 
使用ButterKnife对View对象进行注入,从而无需写findViewById。
 
2.1继承BaseActivity,BaseActivity的实现
 
A.
声明了一个带有Inject注解的成员Navigator
在onCreate方法中,将Navigator依赖注入到当前实例。
 
B.
提供三个protected方法,一个是用来添加fragment到当前界面的某个位置;两个是用来进行依赖注入的。
 
2.2 MainActivity执行流程
用户点击R.id.btn_LoadData Button,就会跳转到界面UserListActivity.
 
3.UserListActivity实现
 
A.
界面加载,使用UserListFragment。
 
B.
在onCreate方法中,执行UserComponent包含的依赖初始化。
  private void initializeInjector() {
    this.userComponent = DaggerUserComponent.builder()
        .applicationComponent(getApplicationComponent())
        .activityModule(getActivityModule())
        .build();
  }
 
UserComponent生成的依赖,被注入到UserListFragment,UserDetailsFragment。UserListFragment,UserDetailsFragment调用UserComponent实例的inject方法。
UserComponent如下:
可以注入到UserListFragment,UserDetailsFragment的依赖是GetUserListUseCase,GetUserDetailsUseCase。
,
/**
* A scope {@link com.fernandocejas.android10.sample.presentation.internal.di.PerActivity} component.
* Injects user specific Fragments.
*/
@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = {ActivityModule.class, UserModule.class})
public interface UserComponent extends ActivityComponent {
void inject(UserListFragment userListFragment);
void inject(UserDetailsFragment userDetailsFragment);
}
/**
* A base component upon which fragment's components may depend.
* Activity-level components should extend this component.
*
* Subtypes of ActivityComponent should be decorated with annotation:
* {@link com.fernandocejas.android10.sample.presentation.internal.di.PerActivity}
*/
@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
//Exposed to sub-graphs.
Activity activity();
}
/**
* A module to wrap the Activity state and expose it to the graph.
*/
@Module
public class ActivityModule {
private final Activity activity; public ActivityModule(Activity activity) {
this.activity = activity;
} /**
* Expose the activity to dependents in the graph.
*/
@Provides @PerActivity Activity activity() {
return this.activity;
}
}
/**
* Dagger module that provides user related collaborators.
*/
@Module
public class UserModule { private int userId = -1; public UserModule() {} public UserModule(int userId) {
this.userId = userId;
} @Provides @PerActivity @Named("userList") UseCase provideGetUserListUseCase(
GetUserListUseCase getUserListUseCase) {
return getUserListUseCase;
} @Provides @PerActivity @Named("userDetails") UseCase provideGetUserDetailsUseCase(
UserRepository userRepository, ThreadExecutor threadExecutor,
PostExecutionThread postExecutionThread) {
return new GetUserDetailsUseCase(userId, userRepository, threadExecutor, postExecutionThread);
}
}
4.UserListFragment的实现
 
A.
UserListFragment实现UserListView接口,用来表示View层。
B.
UserListFragment跟宿主Activity的通信,通过UserListFragment声明的接口UserListListener来实现。
@Override public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof UserListListener) {
this.userListListener = (UserListListener) activity;
}
}
 
C.
当宿主Activity创建成功之后,回调方法:
@Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
this.initialize();
this.loadUserList();
}
在UserListFragment类中,使用Inject注解,声明了一个成员@Inject UserListPresenter userListPresenter;
然后,调用UserComponent实例的方法inject,就可以将依赖userListPresenter注入到UserListFragment实例中。
调用userListPresenter的方法setView,建立Presenter和View之间的关系。
private void initialize() {
this.getComponent(UserComponent.class).inject(this);
this.userListPresenter.setView(this);
}
调用loadUserList方法,会加载所有用户数据。
/**
* Loads all users.
*/
private void loadUserList() {
this.userListPresenter.initialize();
}
界面的数据加载操作,都被封装在userListPresenter的initalize方法中。展示界面加载效果;执行获取数据操作;数据加载成功之后,显示对应的界面。这些都由userListPresenter来实现和控制。
 
5.UserListPresenter
 
A.
调用构造方法,构造方法的参数,由Dagger注入。
@Inject
public UserListPresenter(@Named("userList") UseCase getUserListUserCase, UserModelDataMapper userModelDataMapper) {
this.getUserListUseCase = getUserListUserCase;
this.userModelDataMapper = userModelDataMapper;
}
 
B.
提供initialize方法,供其它类调用。调用该方法,展示界面加载效果;获取所有用户数据。
/**
* Initializes the presenter by start retrieving the user list.
*/
public void initialize() {
this.loadUserList();
} /**
* Loads all users.
*/
private void loadUserList() {
this.hideViewRetry();
this.showViewLoading();
this.getUserList();
}
private void getUserList() {
this.getUserListUseCase.execute(this); //这里使用到了domain层上的类,domain层提供用例类。一个用例类表示一个表示一个业务,在这里表示获取用户列表。 }
6.UserListPresenter和UseCase的协作
 
 
UserListPresenter和UseCase的协作,使用
 
The RxJava Android Module 框架
 
 
1.UserListPresenter属于Presention层,它依赖domain层和data层。
 
2.UseCase是domain层,它的实例是GetUserListUseCase,这个是由Presention层中的依赖定义包指定的,如下:
com.fernandocejas.android10.sample.presentation.internal.di.modules.UserModule:
 
  @Provides @PerActivity @Named("userList") UseCase provideGetUserListUseCase(
      GetUserListUseCase getUserListUseCase) {
    return getUserListUseCase;
  }
 
-----
所以,GetUserListUseCase是必须是可注入的,要在其构造函数中添加@Inject注解。
 
3.UserListPresenter和GetUserListUseCase,UserListPresenter是一个订阅者;这个订阅者订阅的流是CloudUserDataStore实例的方法getUseEntityList()产出来之后,经过映射的流,
该流是长这个样子的:
 
  @Override public Observable<List<User>> getUsers() {
    //we always get all users from the cloud
    final UserDataStore userDataStore = this.userDataStoreFactory.createCloudDataStore();
    return userDataStore.getUserEntityList().map(userListEntityMapper);
  }
 
 
总结牵涉到的类及所在的层:
 
presentation层:UserListPresenter。
domain层: GetUseerListUseCase,UseCase
data层:UserDataRepository,CloudUserDataStore,UserDataStoreFactory
 
presentation层依赖domain层和data层。
 
 
7.整个项目使用到的框架技术
 
1.Dagger依赖生成,定义依赖的生成规则。
2.RxAndroid 响应式编程范式的应用,用事件流的方式来处理异步事件。
3.okHttp,网络请求应用到该框架。
 
8.整个项目阅读下来,可以学习到的东西
 
 
1.使用依赖注入,一个实例包含其它实例,在获取其它实例的使用,使用依赖注入,不将其它实例的生成方式暴露出去。这样,使用者只关注使用,无需关注怎样实例化,其它实例实例化的过程对使用者隐藏掉。
 
2.分层,分模块,这个要针对功能的含义来划分,根据关注点来划分。
presentation层,我们只关注界面展示,我们在这一层里面,我们只需要关注界面展示方面的代码,我们只放界面展示代码在这一层上,还有依赖生成的代码。在这层,我们重点只关注界面代码,还有依赖生成的规则。
 
domain层,领域层,用例层,从这个模块中包的命名就可以知道,它表示抽象程度高的业务,与系统平台无关的业务。在这个应用中,有两个业务,一个是获取用户列表,一个是获取用户的详细信息。
在这一层,存放业务的实现代码。
data层,数据获取,数据存储的实现代码放在这一层。
 
层之间的依赖规则:
presention层------>domain层-------获取数据---->data层
 
参考资料:http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/

例子Architecting Android…The clean way?----代码分析的更多相关文章

  1. Architecting Android…The clean way?

    Architecting Android-The clean way? 原文链接:http://fernandocejas.com/2014/09/03/architecting-android-th ...

  2. Android 4.2启动代码分析(一)

    Android系统启动过程分析 Android系统的框架架构图如下(来自网上):   Linux内核启动之后----->就到Android的Init进程 ----->进而启动Android ...

  3. ironic-conductor与ipa交互clean部分代码分析

    clean的动作会在provide和delete阶段才会触发 从代码分析: 对节点执行的node provide/deleted/clean会先发送到ironicclient ironicclient ...

  4. android recovery 主系统代码分析

    阅读完上一篇文章: http://blog.csdn.net/andyhuabing/article/details/9226569 我们已经清楚了如何进入正常模式和Recovery模式已有深刻理解了 ...

  5. android adb 流程原理代码分析(一)

    由于要用到adb的知识,但是对adb啥也不了解,看了下android的代码,adb的源码在system/core/adb下面,然后网上搜下了资料,发现很多大神的源码分析,瞬间信心爆棚,把大神写的博客都 ...

  6. android recovery 主系统代码分析【转】

    本文转载自:http://blog.csdn.net/andyhuabing/article/details/9248713 阅读完上一篇文章: http://blog.csdn.net/andyhu ...

  7. Android 静态代码分析工具

    简评: 作者在文中提到的三个静态代码分析工具不是互相替代的关系,各有各的侧重点,如果有需要完全可以同时使用. 静态代码分析是指无需运行被测代码,仅通过分析或检查源程序的语法.结构.过程.接口等来检查程 ...

  8. Android代码分析工具lint学习

    1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...

  9. Android艺术——Bitmap高效加载和缓存代码分析(2)

    Bitmap的加载与缓存代码分析: 图片的压缩 比如有一张1024*768像素的图像要被载入内存,然而最终你要用到的图片大小其实只有128*96,那么我们会浪费很大一部分内存,这显然是没有必要的,下面 ...

随机推荐

  1. python执行linux命令的两种方法

    python执行linux命令有两种方法: 在此以Linux常用的ls命令为例: 方法一:使用os模块 1 2 3 shell# python >> import os >> ...

  2. 《学习OpenCV》课后习题解答4

    题目:(P104) 练习使用感兴趣区域(ROI).创建一个210*210的单通道图像并将其归0.在图像中使用ROI和cvSet()建立一个增长如金字塔状的数组.也就是:外部边界为0,下一个内部边界应该 ...

  3. 3dContactPointAnnotationTool开发日志(六)

      一种可行的思路就是枚举一个模型的三角面片,然后判断三角形是否与另一个物体相交即可.为了让效果更好我想只渲染模型的线框.   在网上查了半天好像Unity里都没有自带的方便的渲染线框的方式,我又自己 ...

  4. python获取本地时间

    python本地时间 import time # 格式化成2016-03-20 11:45:39形式 now = time.strftime("%Y-%m-%d %H:%M:%S" ...

  5. 【Docker 命令】- attach命令

    docker attach :连接到正在运行中的容器. 语法 docker attach [OPTIONS] CONTAINER 要attach上去的容器必须正在运行,可以同时连接上同一个contai ...

  6. TCP协议详解7层和4层解析(美团,阿里) 尤其是三次握手,四次挥手 具体发送的报文和状态都要掌握

    如果想了解HTTP的协议结构,原理,post,get的区别(阿里面试题目),请参考:HTTP协议 结构,get post 区别(阿里面试) 这里有个大白话的解说,可以参考:TCP/IP协议三次握手和四 ...

  7. [C/C++] C++类对象创建问题

    CSomething a();// 没有创建对象,这里不是使用默认构造函数,而是定义了一个函数,在C++ Primer393页中有说明. CSomething b(2);//使用一个参数的构造函数,创 ...

  8. BZOJ 1046 上升序列(LIS变形)

    要保证长度为L的序列下标字典序最小,当然要尽量选前面的数. 如何判断前面的数是否满足条件?,只需要知道这个数开头的递增序列的最长长度是多少,如果不小于L,那么必然可以加入这个数.还需判断一下它是否大于 ...

  9. 【bzoj1572】[Usaco2009 Open]工作安排Job 贪心+堆

    题目描述 Farmer John 有太多的工作要做啊!!!!!!!!为了让农场高效运转,他必须靠他的工作赚钱,每项工作花一个单位时间. 他的工作日从0时刻开始,有1000000000个单位时间(!). ...

  10. 【codevs1282】约瑟夫问题 Treap

    题目描述 有编号从1到N的N个小朋友在玩一种出圈的游戏.开始时N个小朋友围成一圈,编号为I+1的小朋友站在编号为I小朋友左边.编号为1的小朋友站在编号为N的小朋友左边.首先编号为1的小朋友开始报数,接 ...