原稿标题,平日支出的烦乱

原来的书文标题:A useful stack on android #1, architecture

正文是如何支付一款拥有扩充性,维护性和测试性的Android应用专题的率先篇。本专题将会涉及到部分设计方式和类库的施用方法,裁减Android
Developer
日常费用的郁闷。

正文是对该文章的翻译,本人翻译水平有限,但是会尽力而为确定保障不会出现显著的逻辑错误,克罗地亚共和国语阅读能力较强的爱人能够直接去看原稿。
该小说的类别首要使用了MVP的情势,并行使了Square的Retrofit和奥托那多个库,那篇小说属于这一名目繁多的首先篇。
说到底再补一句,假若有吗翻译错的,请各位朋友务必提出,不甚谢谢QAQ,若是有啥疑忌欢迎提议,共同研商。

简介:##

作为例子,笔者将动用以下那一个类型,事实上就是八个简便的影视概念目录,能够叫做视图或许别的。

至于电影的音讯能够从三个叫作Themoviedb的公然API中拿走,在这么些版块中Apiary能够找到科学的文档表明。

品类基于Model View
Presenter

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

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

不无代码都足以从Github中收获,所以请随意看,那里同样有1个视频用来展现App。

Paste_Image.png


架构:##

架构的统一筹划基于Model View
Presenter

,它是Model View
Controller

设计情势的一个变种。

那种安插试图抽象Presentation层的业务逻辑,在Android中这是很要紧的,因为本人Framework
提倡那两片段与数码层解耦合,2个显眼的例证就是AdaptersCursorLoaders

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

译文如下:

概述##

这种组织能够被分割为多个第③层次:

  • presentation
  • model
  • domain

Presentation
Presentation层负责提供数据并出示图形化界面。

Model
Model层将承受提供新闻,这一层并不知道Presentation层和Domain,它能够与数据库,REST
API大概其余可持久化数据等落到实处连续。

在这一层,也足以实现部分应用程序的实体类,用来代表,电影,种类等等。

Domain
Domainca88亚洲城官网,层完全部独用立于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')
}

概要

作为例子,小编将动用上面包车型地铁品类,那是二个简单易行的摄像目录,能够被标记为视图大概挂起。

至于电影的新闻是调用那个集体接口
themoivedb,你能在Apiary这一章找到适合的文书档案

本条类型是依照Model View
Presenter
(MVP)方式,也兑现了部分Material
Design
的宏图,比如转场、结构、动画、配色等等。

装有的代码能在github上边下载,那里也有1个视频呈现这么些app的内容

ca88亚洲城官网 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中那是12分首要的,因为我们的框架降低了它与数据层的耦合度,3个掌握的例子正是Adaters大概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
    ca88亚洲城官网 2
    otto

通信##

对此这一个类型,小编接纳了Message
Bus
(译者注:新闻总线)系统,这一个体系对此播放事件,大概在多少个零件之间建立通讯是特别实惠的,尤其特别适用于子孙后代。

基本上,通过Bus出殡事件,对事件感兴趣的类,须要订阅Bus,才能消费十二分事件。

适用这几个系列能够下落模块间的耦合度。

为了落到实处这几个系统总线,小编使用Square出品的Otto类库。

本身定义了七个Bus,叁个用来使usecase和REST
API举行通讯,另2个用来发送事件至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亟待贯彻3个方法,这些主意所接受参数的数据类型必须与Bus发送的事件的数据类型一致,兵器必须运用注明:@Subscribe

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

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

表现层

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

资源:##

模型层

模型负责提供音讯,这一层并不知道domain层和显现层,它能落到实处对数据库的接连和接口,使用REST
API恐怕别的格局

Domain

domain层是一点一滴独立于表现层,它将位于你的选拔的政工逻辑。

实现

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

ca88亚洲城官网 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这几个类表示为1个影视。

它方今只信赖 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系统,那几个系统十一分有用于广播事件,它白手起家了七个零部件之间的通讯。

根本事件都以由此发送三个Bus,要是想去消费有个别Bus,就要求去订阅这么些Bus。

选择这些种类,整个module就会拥有低耦合度。

为了落到实处这么些系统,小编动用了SquareOtto类库。

自身注解了七个Bus,三个用以usecases的REST API
通信,此外1个用于表现层发送事件。

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

相关文章