android应用框架系列一,架构
来源:互联网 发布:网络唤醒电脑 编辑:程序博客网 时间:2024/06/05 04:53
A useful stack on android #1, architecture
02 Feb 2015原文链接:原文地址原文作者:Saúl Molinero
这是一个关于如何设置开发一个可扩展、可维护、可测试的安卓环境主题系列文章的第一篇,在这个系列中,我将介绍一些设计模式和类库的使用方法避免android开发者在日常开发中感到发狂。
Scenario
在例子中我将会依赖以下项目,一个简单电影分类项目做概念验证,一个能被标记作为视图或挂起的项目。
电影的有关信息是调用themoviedb 这个公共接口,你能在 Apiary里找到详细的文档。
这个项目基于 Model View Presenter 设计模式,也实现了一些 Material Design 的设计,像页面转换、结构、动画、颜色、等等。。。
所有的可用代码在 Github, 可以随意看看,同时这里也有一个 视频展示这个应用的行为。
Architecture
在架构设计中我采用了设计模式:Model View Presenter,是Model View Controller模式的演变模式。
这种模式尝试去抽象表现层的业务逻辑,这在android中是很重要的,因为在我们的框架促进了这两部分与数据层的耦合,一个清晰的例子是 Adapters 或者CursorLoaders.
这种架构促使替换界面不需要修改业务逻辑层和数据层。这样就可以很简单的去重用代码或者改变不同的数据源例如数据库和REST API。
Overview
架构可以被分割为三个主要的层:
- presentation
- model
- domain
Presentation
表现层是负责显示图形界面和为其提供数据。
Model
模型层是负责提供信息,这一层不知道领域和表现层的内容,可以实现一个数据库的连接和接口、REST API、或者其它任何数据持久的方式。
在这一层同样实现了应用的的实体类,表示一个电影的类,类别等等。。。
Domain
领域层完全独立与表现层,它里面是属于应用的业务逻辑。
Implementation
在Android 应用里,domain 和 model 层是分离的两个java模块,presentation层由app模块代表,还有一个common模块是用来提供公共类库和工具类的。
Domain module
在domain模块里存放着用例和它们的实现,是应用的业务逻辑。
这个模块完全独立于android框架。
他依赖于model模块和common模块。
一个用例需要获得各种主题电影的总评分,看看哪一类最受欢迎,用例需要获得电影信息然后做出计算,电影信息由model层提供。
dependencies { compile project (':common') compile project (':model')}
Model module
model module负责管理信息,选择、保存、删除信息等等。。。在第一个版本我仅仅管理电影信息API的操作。
它同样实现了实体类,例如TvMovie
,表示一个电影。
这个模块至今只依赖common模块,这个类库被用来管理API的请求,这样我需要使用Square的Retrofit,我会在下面介绍retrofit。
dependencies { compile project(':common') compile 'com.squareup.retrofit:retrofit:1.9.0'}
Presentation module
是Android应用本身的模块,有自己resources, assets, 逻辑等。。。
他也与domain通过运行的用例互相作用,在例子中需要获取某一时间的当前电影列表,或者从电影请求具体的数据。
在这个模块里有presenters 和 views。
每个Activity
, Fragment
, Dialog
, 都实现一个 MVPView
接口,它指定了显示、隐藏、打印信息等需要支持显示的操作。
例如,PopularMoviesView
视图接口指定了显示当前电影的列表的操作,由MoviesActivity
类实现这些方法。
public interface PopularMoviesView extends MVPView { void showMovies (List<TvMovie> movieList); void showLoading (); void hideLoading (); void showError (String error); void hideError ();}
模式:MVP 中的视图尽可能简单,presenter决定视图的行为。
public class MoviesActivity extends ActionBarActivity implements PopularMoviesView, ... { ... private PopularShowsPresenter popularShowsPresenter; private RecyclerView popularMoviesRecycler; private ProgressBar loadingProgressBar; private MoviesAdapter moviesAdapter; private TextView errorTextView; @Override protected void onCreate(Bundle savedInstanceState) { ... popularShowsPresenter = new PopularShowsPresenterImpl(this); popularShowsPresenter.onCreate(); } @Override protected void onStop() { super.onStop(); popularShowsPresenter.onStop(); } @Override public Context getContext() { return this; } @Override public void showMovies(List<TvMovie> movieList) { moviesAdapter = new MoviesAdapter(movieList); popularMoviesRecycler.setAdapter(moviesAdapter); } @Override public void showLoading() { loadingProgressBar.setVisibility(View.VISIBLE); } @Override public void hideLoading() { loadingProgressBar.setVisibility(View.GONE); } @Override public void showError(String error) { errorTextView.setVisibility(View.VISIBLE); errorTextView.setText(error); } @Override public void hideError() { errorTextView.setVisibility(View.GONE); } ...}
这个用例由presenters执行,它将会接收response 和管理views的行为。
public class PopularShowsPresenterImpl implements PopularShowsPresenter { private final PopularMoviesView popularMoviesView; public PopularShowsPresenterImpl(PopularMoviesView popularMoviesView) { this.popularMoviesView = popularMoviesView; } @Override public void onCreate() { ... popularMoviesView.showLoading(); Usecase getPopularShows = new GetMoviesUsecaseController(GetMoviesUsecase.TV_MOVIES); getPopularShows.execute(); } @Override public void onStop() { ... } @Override public void onPopularMoviesReceived(PopularMoviesApiResponse popularMovies) { popularMoviesView.hideLoading(); popularMoviesView.showMovies(popularMovies.getResults()); }}
Communication
这个项目我选择了一个消息总线系统,这个系统在广播事件和建立两个组件之间的通信非常有用,尤其是后者配合的十分完美。
主要的事件都通过总线发送,感兴趣的消费类需要在总线订阅。
使用这个系统,模块之间将会有一个低耦合度。
我使用Square的类库Otto实现这个系统。
我定义了两个总线,一个使用REST API和用例通信,另一个向表现层发送事件。
REST_BUS
使用任何线程处理事件,UI_BUS
发送事件通过主线程(默认UI主线程)。
public class BusProvider { private static final Bus REST_BUS = new Bus(ThreadEnforcer.ANY); private static final Bus UI_BUS = new Bus(); private BusProvider() {}; public static Bus getRestBusInstance() { return REST_BUS; } public static Bus getUIBusInstance () { return UI_BUS; }}
这个类由common模块管理,因为所有的模块都会获取它并与主线互相作用。
dependencies { compile 'com.squareup:otto:1.3.5'}
最后,思考下面的例子,在用户打开应用的时候显示最受欢迎的电影。
当 onCreate
方法在 Android View
调用时,presenter 在UI_BUS上订阅接收事件, onStop()
方法调用时presenter取消自身订阅,例如 presenter 运行 GetMoviesUseCase
用例。
@Override public void onCreate() { BusProvider.getUIBusInstance().register(this); Usecase getPopularShows = new GetMoviesUsecaseController(GetMoviesUsecase.TV_MOVIES); getPopularShows.execute(); } ... @Override public void onStop() { BusProvider.getUIBusInstance().unregister(this); }}
当总线发送事件时,presenter要接收事件,必须实现一个有相同数据类型的参数的方法,而且必须使用注解:@Subscribe
。
@Subscribe @Override public void onPopularMoviesReceived(PopularMoviesApiResponse popularMovies) { popularMoviesView.hideLoading(); popularMoviesView.showMovies(popularMovies.getResults()); }
Resources:
Architecting Android…The clean way? - Fernando Cejas
Effective Android UI - Pedro Vicente Gómez Sanchez
Reactive programming and message buses for mobile - Csaba Palfi
The clean architecture - Uncle Bob
MVP Android - Antonio Leiva
- android应用框架系列一,架构
- Spring框架系列(一)-整体架构
- Android架构系列-MVP架构的实际应用
- android应用框架系列二,图形界面
- android应用框架系列三,兼容性
- Android多媒体应用开发系列(一) 拍照
- android应用开发MVC框架(一)
- 应用开发工程依赖Jar包系列(一)--Spring框架
- Android应用架构系列——ListView的模板化
- Android系统架构剖析(二)之应用框架演变
- Android应用架构的一些思考-框架模块化
- Android网络框架之基本架构(一)
- 一个实用的android框架(一)——架构
- Android架构设计02-网络请求框架(一)
- 架构设计EIT造型下的android框架(一)
- Android搭建应用框架系列之Retrofit封装
- Android系列一:Android应用开发基础知识篇
- 搭建高质量的Android项目框架系列一
- CocoaPods的安装和使用
- 电信免费手机卡iFree黄金版使用须知(四)
- Java7中的switch...case支持string的实现细节
- struts2配置文件解析
- 富文本Attributes详解
- android应用框架系列一,架构
- Loaders && Overview Screen
- 去除空白cell的分割线
- ARM CPU总结
- tomcat部署项目
- 如何利用cookie实现html页面的记住密码
- 查看linux中某个端口(port)是否被占用(netstat,lsof)
- NSThread的使用
- 守护线程