初稿标题:A useful stack on android #1, architecture

本文是怎么着开发一款有着扩张性,维护性和测试性的Android应用专题的第3篇。本专题将会涉及到有些设计格局和类库的运用办法,收缩Android
Developer
常备开支的烦躁。

正文是对该文章的翻译,自身翻译水平有限,可是会尽也许保证不会并发鲜明的逻辑错误,塞尔维亚(Република Србија)语阅读能力较强的爱侣能够直接去看原稿。
该小说的连串首要行使了MVP的情势,并应用了Square的Retrofit和奥托那七个库,那篇著作属于这一雨后春笋的第1篇。
最后再补一句,假使有何翻译错的,请各位朋友务必建议,不甚感谢QAQ,即便有啥怀疑欢迎建议,共同商讨。

简介:##

用作例子,笔者将选取以下那一个类型,事实上就是1个不难的电影和电视概念目录,能够称为视图大概别的。

有关电影的新闻方可从七个称作Themoviedb的公开API中收获,在这么些版块中Apiary能够找到科学的文书档案表达。

类型基于Model View
Presenter

设计情势,也参照了有的Material
Design

设计规范,比如转场,(界面)结构,动画,配色等等。

装有代码都足以从Github中取得,所以请随意看,那里同样有三个视频用来显示App。

Paste_Image.png


架构:##

框架结构的布置基于Model View
Presenter

,它是Model View
Controller

设计方式的二个变种。

这种规划试图抽象Presentation层的事情逻辑,在Android中那是很重点的,因为笔者Framework
提倡那两局部与数量层解耦合,3个显眼的例证就是AdaptersCursorLoaders

那种架构促使业务逻辑层和数据层不再随着视图层的转移而变更,那样无论Domain层的代码复用还是例如Database或者REST
API
等数据源的改观,都变得简单起来。

译文如下:

概述##

那种结构得以被分开为八个首要层次:

  • presentation
  • model
  • domain

Presentation
Presentation层负责提供数据并突显图形化界面。

Model
Model层将担当提供音讯,这一层并不知道Presentation层和Domain,它亦可与数据库,REST
API只怕别的可持久化数据等落到实处延续。

在这一层,也得以兑现部分应用程序的实体类,用来表示,电影,类别等等。

Domain
Domain层完全部独用立于Presentation层之外,这一层专门处管事人务逻辑。

那是本类别的第②篇小说,本体系将介绍怎么着布署环境去支付多少个富有可扩充性、可维护性和可测试性的花色,在本类别中,小编将富含一些情势和以及类库的采用使安卓开发者在经常中不会疯狂。

实现##

Domain层和Model层被放到三个java module中,app
module也正是Android应用代表Presentation层,那里还有其它二个common
module,用来存放一些集体类库和工具类们。

Domain module

Domain
module存放着一些usecase和它们的落到实处类,它们是应用程序的事务逻辑。

本条module完全部独用立于Android framework

借助于它的模块有model module和common module。

一个usecase能够用来获得分裂品类电影的总评分,看一看哪个项目标影视最受欢迎,usecase内需获取消息然后做出总结,全体这几个新闻都由Model层提供。

dependencies {
    compile project (':common')
    compile project (':model')
}

概要

用作例子,笔者将应用上面包车型地铁花色,那是1个差不离的电影目录,能够被标记为视图大概挂起。

至于电影的音信是调用那么些集体接口
themoivedb,你能在Apiary这一章找到确切的文档

以此类型是基于Model View
Presenter
(MVP)形式,也促成了有的Material
Design
的宏图,比如转场、结构、动画、配色等等。

负有的代码能在github下面下载,这里也有3个视频展现那些app的剧情

图片 1

App展示

Model module##

model
module负责处理音信,查询,保存,删除等等,笔者只处理了从API获取电影详情的操作。

也促成了部分实体类,比如TvMovie,用来显示一部影视。

它近来只信赖common
module,通过这些类库处理API请求,在那么些事例中本人使用Square出品的Retrofit,小编将在接下去的博客中介绍Retrofit。

dependencies {
    compile project(':common')
    compile 'com.squareup.retrofit:retrofit:1.9.0'
}

架构:

本条架构的布署是依据MVP方式,MVP形式是MVC方式的一种衍生和变化

那种方式尝试去抽象表现层的事务逻辑,在Android中那是至极重庆大学的,因为大家的框架降低了它与数据层的耦合度,多个知晓的例证正是艾达ters只怕CursorLoaders。

那种架构促使,视图层的变化不须要修改工作逻辑层和数据层。那样就很简短的复用代码恐怕转移种种三种的数据源,比如数据库或然REST
API

翻译注:以上只是对MVP情势的简易介绍

Presentation module##

纵使Android应用自己,包含resources, assets, 逻辑等等。

它与执行usecaseDomain开始展览互相,比如能够用来获得某一时分的电影列表,或然从有个别电影中赢得特殊的多少。

以此模块只包罗PresenterView

每一个ActivityFragmentDialog都实现MVPView接口,它钦定了部分在View上展开始展览示,隐藏,显示消息等操作。

比如,PopularMoviesView经过点名一些操作呈现当前影视列表,然后MoviesActivity实现它。

public interface PopularMoviesView extends MVPView {

    void showMovies (List<TvMovie> movieList);

    void showLoading ();

    void hideLoading ();

    void showError (String error);

    void hideError ();
}

MVP设计格局正是让View变得硬着头皮的粗略,由Presenter支配它们的作为。(译者注:View层应彰显KISS规范,感兴趣的校友能够领悟一下Keep
it simple stupid

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);
    }

    ...
}

这个usecase通过Presenter调用,并且Presenter收纳相应结果,然后处理View上的呈现。

概述

那种架构会分成三层:

  • presentation(也正是上文平素翻译的展现层)
  • model
  • domain
    图片 2
    otto

通信##

对此这么些项目,作者选拔了Message
Bus
(译者注:新闻总线)系统,那一个系统对此播放事件,也许在八个零件之间确立通讯是格外有效的,特别尤其适用于子孙后代。

基本上,通过Bus发送事件,对事件感兴趣的类,须要订阅Bus,才能消费11分事件。

适用这些系统能够下跌模块间的耦合度。

为了贯彻这一个系统总线,笔者动用Square出品的Otto类库。

自个儿定义了四个Bus,二个用来使usecase和REST
API实行通讯,另贰个用来发送事件至Presentation
层。

REST_BUS行使任意线程处总管件,UI_BUS采用默许线程发送事件,那么些线程正是主线程。

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
module管理。因为具有的模块都急需拜访它,从而与Bus拓展互动。

dependencies {
    compile 'com.squareup:otto:1.3.5'
}

末段,想象一下以此情景,当用户打开应用,突显最受欢迎的影片。

View调用onCreate()方法时,Presenter订阅UI_BUS接受事件。当onStop()方法被调用的时候Presenter裁撤订阅。Presenter运行GetMoviesUseCase这个usecase

@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急需实现1个措施,那一个点子所收受参数的数据类型必须与Bus出殡的轩然大波的数据类型一致,兵器必须选用注明:@Subscribe

@Subscribe
    @Override
    public void onPopularMoviesReceived(PopularMoviesApiResponse popularMovies) {

        popularMoviesView.hideLoading();
        popularMoviesView.showMovies(popularMovies.getResults());
    }

表现层

这个表现层是背负去显示图形和提供数据

资源:##

模型层

模型负责提供音讯,这一层并不知道domain层和显示层,它能兑现对数据库的连日和接口,使用REST
API只怕其余措施

Domain

domain层是一点一滴独立于表现层,它将身处你的使用的事情逻辑。

实现

domain层和模型层被分成四个module,表现层在主app的module,还有一个叫common的module,用来放一些类库和工具类。

图片 3

app架构图

Domain module

domain module 有着usecases和它的落到实处类,那是当做利用的事务逻辑

这一个模块是完全部独用立于Android框架

它是依靠于 model module 和 common module。

usecase 能够赢得各类电影的评级,看看哪类是最受欢迎的。usecase
会要求获得电影的音讯并盘算,将那个信息提须求model。

dependencies {
    compile project (':common')
    compile project (':model')
}

Model module

Model module
是负担对消息的保管,增加和删除改查等等,在率先个版本小编只有对影片api的新闻实行政管理理。

它也兑现了实体,比如TvMovie那个类表示为多少个影视。

它近来只倚重 common
module,这几个类库被用来治本API的伸手,那里小编使用了SquareRetrofit,小编将在下文介绍Retrofit。

Presentation module

那正是app自个儿,有着resources, assets ,逻辑等等。

它也与 domain 正在运营的 usecases
相互影响着,比如,想取得某些特定时间的影视照旧一部影视的钦命时间。

在这个module中有着 presentersviews

各样Activity,Fragment,Dialog都落到实处了MVPView接口,它内定了在View上进展显示、隐藏和画画新闻的操作。

举个例证,PopularMoviesView内定了呈现当前电影列表的操作,并让MoivesActivity达成那几个方法。

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);
    }

    ...
}

usecase 将被 presenter 执行,他们将接受响应并对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());
    }
}

通讯

那个类型中本身接纳了1个Message
Bus系统,这一个体系相当有用于广播事件,它创建了五个零件之间的通讯。

重庆大学事件都以因此发送2个Bus,假设想去消费某些Bus,就要求去订阅这几个Bus。

选用那几个种类,整个module就会持有低耦合度。

为了贯彻这么些体系,作者利用了SquareOtto类库。

自个儿注明了多少个Bus,贰个用以usecases的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
module,因为有着的module能够访问它,并与bus相互影响。

dependencies {
    compile 'com.squareup:otto:1.3.5'
}

最后,思考下边包车型客车例证,在用户打开App的时候显得多数受欢迎的录制。

OnCreate方法被Android视图调用的时候,这一个presenter订阅UI_BUS用来接受事件。那一个presenter在OnStop格局被调用的时候解除订阅,这一个presenter运转着GetMoivesSerCase.

@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());
    }

相关文章