例子Architecting Android…The clean way?----代码分析

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. */@Modulepublic 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. */@Modulepublic 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. */@Modulepublic 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注入。

@Injectpublic 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/
时间: 2024-10-13 09:03:12

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

Architecting Android…The clean way?

Architecting Android-The clean way? 原文链接:http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/原文作者:Fernando Cejas 过去几个月,与@pedro_g_s 和 @flipper83 (顺嘴说一下这两位是android开发大牛)两位同行在Tuenti 站点上友好的讨论之后.我觉得这是一个写一篇关于android应用架构的文章的好时机. 写这篇文章的目的是想

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

由于要用到adb的知识,但是对adb啥也不了解,看了下android的代码,adb的源码在system/core/adb下面,然后网上搜下了资料,发现很多大神的源码分析,瞬间信心爆棚,把大神写的博客都浏览了一遍,然后手动运行了下adb命令,顺便跟踪了下过程,发现原来还是很好的理解,源码的各种线程创建,函数回调,对于我这种基础不咋好的,,还是看的晕晕呼呼,现在把我自己的理解给大家分享,有理解错误的还请多多指正. 一般直接上代码,可能看官都走了一大半,我们逆向的看,先看结果,再看过程,最后再看代码.

SDL2.0例子代码分析-----CheckKeys Project

SDL简介 SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成.SDL提供了数种控制图像.声音.输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux.Windows.Mac OS X等)的应用软件.目前SDL多用于开发游戏.模拟器.媒体播放器等多媒体应用领域. SDL1.2和SDL2的差别 SDK1.2和SDL2.1系列的API接口变动的不小,当然功能也大大增强,支持多线程窗口. 具体的change 请看 h

TeamTalk Android代码分析(业务流程篇)

TeamTalk Android代码分析(业务流程篇) 1.1 总体结构 1.总体结构有点类似MVC的感觉,模块结构从上向下大体是: UI层:Activity和Fragment构成,期间包括常用的一些开源控件如:imageloader,speedx,gifview等,和下层数据变更通知通过总线事件完成(EventBus) 管理层:Service(即:imservice,下文均采用此称呼)和一些按照业务划分的Manager(loginmanager,contactmanager,sessionma

如何分析android的OOM,与java静态代码分析工具

用MAT分析OOM 很多OOM看似发生在bitmap 分配得时候,但它一般不是rootcause.根本原因都在于本应该自动释放的资源,因为代码的错误,而导致某些对象一直被引用(Reference),例如 Android 内存优化,如何避免OOM 文章中提到的Activity 的mContext 引用. 当代码量很庞大的时候,单靠读代码查找错误是很困难的,所以必须借助于工具,这里介绍一款很好用的分析工具MAT. 1.下载MAT http://www.eclipse.org/mat/download

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

Bitmap的加载与缓存代码分析: 图片的压缩 比如有一张1024*768像素的图像要被载入内存,然而最终你要用到的图片大小其实只有128*96,那么我们会浪费很大一部分内存,这显然是没有必要的,下面是一个实例: public static int calculateInSampleSize(              BitmapFactory.Options options, int reqWidth, int reqHeight) {      // Raw height and widt

Android恶意代码分析与渗透测试

这篇是计算机类的优质预售推荐>>>><Android恶意代码分析与渗透测试> 从环境构建到分析,涵盖服务体系全过程:以线上线下技巧为基础,展现虚拟环境渗透测试真方法 编辑推荐 从环境构建到分析,涵盖服务体系全过程 以线上/线下技巧为基础,展现虚拟环境渗透测试真方法 内容简介 本书由"恶意代码分析"和"移动服务诊断"两大主题组成.各章节包含了分析步骤,作者们还亲自编写了黑客大赛应用程序试题,读者可以借此复习学过的内容. Androi

新版Android代码分析,生成的代码都有什么用?

刚开始学习,新手,欢迎拍砖和鄙视. 直接入题,新版Android的主要代码分析: 1 package com.bslk.helloworld; 2 /*1.这里的导入包,会有报警告的地方,因为没有使用,已干掉了,其他不管,现在应该0Err0Warn*/ /*2.这是一些导入的包,具体的不解释,不纠结,不懂自己度娘,问了我会鄙视你的*/ 3 import android.support.v7.app.ActionBarActivity; 4 import android.support.v4.ap

Android Bitmap 开源图片框架分析(精华三)

主要介绍这三个框架,都挺有名的,其他的框架估计也差不多了 Android-Universal-Image-Loaderhttps://github.com/nostra13/Android-Universal-Image-Loader ImageLoaderhttps://github.com/novoda/ImageLoader Volley(综合框架,包含图片部分)https://github.com/mcxiaoke/android-volley 扯淡时间,可以跳过这段这些开源框架的源码还