A practical Android Framework (i)--architecture

Source: Internet
Author: User

Original source: Http://saulmm.github.io/2015/02/02/A%20useful%20stack%20on%20android%20%231,%20architecture/

Original code github address: Https://github.com/saulmm/Material-Movies

Saúl Molinero

Translator Note: This is a recent exposure to a project on the Android architecture, but also based on the MVP, the idea of subcontracting and I more fit. In addition, the project is also using the material Design, feeling relatively new and practical. Therefore, decided to the project corresponding to the blog translation, for everyone's reference.

This is the first chapter in this article, which describes how to build a basic environment for developing an extensible, maintainable, and testable Android project. In this section, I'll show you some of the patterns and tools used in the library. These patterns and libraries ensure that your project does not become out of control due to daily development.

Scene

I will explain the following project as an example. This project is a simple movie classification app that supports a variety of ways in which a movie is tagged (read and coming soon).

The data for the movie is obtained from an API called Themoviedb public. For a description of the API, you can get a complete document from Apiary.

This project is based on the Model-view-presenter model and also implements some features of the material design, such as transition effects, UI structure, animations, colors, etc.

All the code is on GitHub and can be downloaded or read at will. At the same time, there is also a video to show the effect of the app.

Architecture

This architecture is designed to be MVP-based. MVP is a transformation of an MVC architecture.

The MVP architecture tries to pull the business logic out of the presentation layer (Presenter). In Android, this is a very important process. Because the architecture of Android itself is also facilitating the separation of business logic and presentation parts, the two are connected through the data plane. A few typical examples are adapter and Cursorloader.

This architecture allows changes to the view to be made without affecting the business logic layer and the data layer. It also makes it easy to reuse domain and conversion tools that are responsible for converting multiple data sources (databases or rest APIT).

Overview

The overall architecture can be divided into three parts:

    • Presentation
    • Model
    • Domain

Presentation

The presentation layer is responsible for displaying the graphical interface and populating the data.

Model

The model layer is responsible for providing the data. The model layer will not know any data about domain and presentation. It can be used to implement a connection or interface to a data source (database, rest API, or other source).

This level also implements the entity classes required by the entire app, such as those used to represent movies or classifications.

Domain

The domain layer is completely independent of the presentation layer, which implements the app's business logic. (Translator Note: Here the so-called business logic may be a bit confusing with presenter's functional concept.) For example, if UseCase received a JSON string containing a list of movies, then the JSON string is converted to JSON and packaged into a ArrayList, which should be done by UseCase. If the size of the ArrayList is 0, that is, the list is empty, the default diagram needs to be displayed, and this judgment and control should be done by presenter. )

Realize

The domain and model layers are placed in two Java modules (the translator notes: It means there will be no Android dependencies), and the presentation layer is the default app module, the so-called Android app. At the same time, I added a generic module to share support libraries and tool classes directly in each module.

Domain Module

The domain module stores some usecase and their implementations. These are implementations of the application business logic. This module is completely independent relative to the Android framework. Its dependence comes only from the model module and the generic module.

A usecase can be used to get the total score for each movie category, which is used to get the most popular classification. To achieve this, usecase may need to obtain data and perform calculations. The data is provided by the model module.

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

Model Module

The Model module is responsible for managing the data, such as obtaining, saving, deleting and so on. In the first version, I just managed the movie data through the rest API.

At the same time, this module also implements some entity classes. For example TvMovie , it is used to denote a movie.

Its dependency is only a generic module and a support library for initiating network requests. On this feature, I used the retrofit developed by Square. I'll introduce retrofit in the next blog post.

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

Presentation Module

This module is the Android app itself, including his resource,asset and logic. It also interacts with the domain layer by running usecase. For example: Get a list of movies for a period of time and request specific data for a movie.

This module contains the presenter and view. Each and every one of Activity Fragment Dialog them implements the view interface in an MVP. This interface specifies the actions that a view needs to support, including displaying, hiding, and displaying the data. For example PopularMoviesView , the interface is defined to show the current movie list, and the specific implementation is MoviesActivity done by.

public interface PopularMoviesView extends MVPView {    void showMovies (List<TvMovie> movieList);    void showLoading ();    void hideLoading ();    void showError (String error);    void hideError ();}

The MVP model was designed to be: the simpler the view, the better, the view behavior should be determined by presenter, not the view itself.

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 Popularsho        Wspresenterimpl (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 (Movieli        ST);    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 is executed in presenter, presenter receives the returned data and controls the view's behavior based on the data.

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

In this project, I chose the message bus (Messagebus) system. This system is very useful for sending broadcast events or establishing communication in each module. And that's exactly what we need. Simply put, the event is sent to the bus, and the class that needs to handle the event must subscribe to the bus event. Using this system can greatly reduce the coupling between modules.

To implement the bus for this system, I used the library Otto developed by Square. I have declared two buses, one (Rest_bus) to implement direct communication between the UseCase and REST APIs, and the other (Ui_bus) sends events to the presentation (presentation) layer. Where Rest_bus will use any available thread to handle the event, and Ui_bus will only send the event to the default thread, the main UI thread.

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

This class is managed by a common module because all modules have dependencies on the module and can operate the bus via this module.

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

Finally, consider a situation in which the most popular movies are first shown when the user opens the app.

When onCreate the method is called, presenter subscribes to Ui_bus to listen for events. The presenter then executes GetMoviesUseCase to initiate the request. Presenter will onStop cancel the subscription when it is called.

@Overridepublic void onCreate() {    BusProvider.getUIBusInstance().register(this);    Usecase getPopularShows = new GetMoviesUsecaseController(GetMoviesUsecase.TV_MOVIES);    getPopularShows.execute();}...@Overridepublic void onStop() {    BusProvider.getUIBusInstance().unregister(this);}

In order to receive an event, presenter must implement a method. The parameters of this method must be the same as the parameters of the event fed into the bus. And this method must be annotated with annotations @Subsribe

@Subscribe@Overridepublic void onPopularMoviesReceived(PopularMoviesApiResponse popularMovies) {    popularMoviesView.hideLoading();    popularMoviesView.showMovies(popularMovies.getResults());}
Reference
    • Architecting Android ... The clean? -Fernando cejas Chinese link
    • 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
Translator Summary

The authors of this project also refer to a set of templates that have been summed up after several notable Android architectures. In architecture and subcontracting, and my thoughts on Android Architecture Combat (a)-the core idea is more fit, streamlined than a complete set of processes, and more suitable for small teams (1-3 people) development.

The difference is that this project uses the event bus to implement inter-module communication. Regarding the comparison between the event bus and the Rxjava, the individual feels that the event bus is relatively simple to understand. But the drawback of the event bus is that the dependency relationship is weak, that is, you can't easily find out who initiated the event. This effect, on the one hand can be understood as low coupling, on the one hand may also cause maintenance when the "lost" phenomenon. Therefore, I am still more inclined to Rxjava design pattern.

There are two additional chapters on this project, mainly on material design and its compatibility issues. Not particularly deep, but if you need the same UI effect, you can make reference, I will translate it, convenient for everyone to find.

A practical Android Framework (i)--architecture

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.