• 原稿链接:A useful stack on android #1,
    architecture
  • 原文作者:
    Saúl
    Molinero
  • 译文出自:
    小鄧子的简书
  • 译者: 小鄧子

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

正文是怎开发同慢慢悠悠具扩展性,维护性和测试性的Android应用专题的第一篇。本专题将会提到到部分设计模式和类库的应用办法,减少Android
Developer
万般支付的苦恼。

本文是本着该文章的翻,本人翻译水平有限,但是会尽量保证不见面并发显著的逻辑错误,英语阅读能力较强的冤家可一直去押原稿。
拖欠篇的路重要采用了MVP的模式,并采取了Square的Retrofit和Otto这简单单仓库,这首文章属于这等同多元之首先首。
末段重复上一句,如果发生何翻译错的,请各位朋友务必指出,不很感激QAQ,如果生吗疑惑欢迎提出,共同讨论。

简介:##

当例子,我用使用以下这项目,事实上就是是一个大概的录像概念目录,可以称呼视图或者其他。

关于影片之信息可起一个曰Themoviedb的明白API中获取,在是版块中Apiary足找到科学的文档说明。

类型基于Model View
Presenter

设计模式,也参照了一部分Material
Design

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

所有代码都可以从Github惨遭得到,所以告随意看,这里同样有一个视频故此来显示App。

Paste_Image.png


架构:##

搭的计划性基于Model View
Presenter

,它是Model View
Controller

设计模式的一个变种。

这种计划试图抽象Presentation臃肿的业务逻辑,在Android中及时是可怜关键之,因为自Framework
提倡这片片与数层解耦合,一个眼看的事例就是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')
}

概要

作为例子,我用祭下面的类别,这是一个略的录像目录,能够被记为视图或者挂起。

关于电影之音讯是调用这个集体接口
themoivedb,你能在Apiary随即同一段找到确切的文档

其一类别是根据Model View
Presenter(MVP)模式,也兑现了有的Material
Design的统筹,比如转场、结构、动画、配色等等。

有着的代码能在github上面下载,这里为时有发生一个视频著这个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中及时是雅重大之,因为咱们的框架降低了它们跟数据层的耦合度,一个明亮的事例就是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
    皇冠娱乐场 2
    otto

通信##

对于此类别,我选择了Message
Bus
(译者注:消息总线)系统,这个体系对此播放事件,或者在简单单零部件之间成立通信是可怜实用的,尤其特别适用于后世。

基本上,通过Bus发送事件,对事件感兴趣的类,需要订阅Bus,才能够花十分事件。

适用是体系可落模块间的耦合度。

为兑现此系统总线,我用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要实现一个方,这个点子所接受参数的数据类型必须和Bus发送的风波之数据类型一致,兵器必须下注解:@Subscribe

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

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

表现层

这个表现层举凡当夺变现图形和提供数据

资源:##

  • 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

模型层

范负责提供信息,这无异层并不知道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的请,这里自己动用了Square的Retrofit,我用于下文介绍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());
    }
}

通讯

夫类别蒙本人选了一个Message
Bus系统,这个系统很有用于广播事件,它白手起家了少于个零部件之间的通信。

着重事件还是经过发送一个Bus,如果想去花有Bus,就待去订阅者Bus。

使是体系,整个module就会有着低耦合度。

以落实者系统,我以了Square的Otto类库。

自声明了少单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());
    }

相关文章