A Practical android framework (I)-architecture, android framework architecture

Source: Internet
Author: User
Tags string to json

A Practical android framework (I)-architecture, android framework architecture

Source: http://saulmm.github.io/2015/02/02/A%20useful%20stack%20on%20android%20%231,%20architecture/

Source code github address: https://github.com/saulmm/Material-Movies

Author: Sa úl Molinero

Note: This is a recent project on Android architecture. It is also based on MVP, And the subcontracting ideas are quite compatible with me. In addition, Material Design is also used for this project, which is novel and practical. Therefore, we decided to translate the blog corresponding to this project for your reference.

This is the first chapter in this article. It describes how to build a basic environment for developing an extensible, maintainable, and testable android project. In this section, I will introduce some of the modes and tool libraries used. These models and libraries ensure that your project will not become out of control due to daily development.

Scenario

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

Movie data is obtained from a public API themoviedb. You can obtain a complete document from Apiary about the API description.

This project is based on the Model-View-Presenter mode, and also implements some Material Design features, such as transition effect, UI structure, animation, and color.

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 based on MVP. MVP is a change in the MVC Architecture.

The MVP architecture tries to extract the business logic from the presentation layer (Presenter. In android, this is a very important process. Because the android architecture is also promoting the separation of business logic and presentation, the two are connected through the data layer. Several typical examples are Adapter and CursorLoader.

This architecture makes modifications to the view unnecessary to affect the business logic layer and data layer. The domain and conversion tools responsible for converting multiple data sources (databases or rest apit) can be easily reused.

Overview

The overall architecture can be divided into three parts:

  • Presentation
  • Model
  • Domain

Presentation

The Presentation layer displays graphical interfaces and fills in data.

Model

The Model layer provides data. The Model layer does not know any data about Domain and Presentation. It can be used to connect to data sources (databases, REST APIs, or other sources) or interfaces.

At the same time, this layer also implements the entity classes required by the entire app, such as classes used to represent movies or categories.

Domain

The Domain layer is completely independent from the Presentation layer and implements the business logic of the app. (Translator's note: here the so-called business logic may be somewhat confused in terms of the Presenter function. For example, if usecase receives a json string containing a list of movies, convert the json string to json and package it into an ArrayList, this should be done by usecase. If the size of the ArrayList is 0, that is, the list is empty, the default graph needs to be displayed. This judgment and control should be done by the presenter .)

Implementation

Domain and Model layers are placed in two java modules respectively (note: this means that there is no android dependency). The Presentation layer is the default app module, which is also called an android Application. At the same time, I added a common module to share the support library and tool classes directly in each module.

Domain Module

The Domain module stores some usecases and their implementations. These are the implementation of application business logic. This module is completely independent from the android framework. Its Dependency only comes from the model module and general module.

A usecase can be used to obtain the total score of each category of a movie, so as to obtain the most popular category. To implement this function, usecase may need to obtain data and perform computation. Data is provided by the model module.

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

Model Module

The Model module manages data, such as data acquisition, storage, and deletion. In the first version, I used the REST API to manage movie data.

At the same time, this module also implements some entity classes. For exampleTvMovieIs used to represent a movie.

It depends only on the common module and the support library used to initiate network requests. For this feature, I used the feature FIT developed by Square. I will introduce Retrofit in the next blog.

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

Presentation module

This module is the android application, including its resource, asset, and logic. It also interacts with the domain layer by running usecase. For example, you can obtain a list of movies within a period of time and request the specific data of a movie.

This module contains presenter and view. EveryActivity,FragmentAndDialogBoth implement the View Interface in an MVP. This interface specifies the operations that a View needs to support, including displaying, hiding, and displaying data. For example:PopularMoviesViewDefines an interface to display the current list of movies.MoviesActivityCompleted.

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

The MVP mode was designed to make the View simpler and better. The View behavior should be determined by the Presenter, rather than 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 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 will be executed in the presenter. The presenter will accept the returned data and control the view 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 MessageBus system. This system is very helpful for sending broadcast events or establishing communication in each module. This is exactly what we need. Simply put, an event is sent to the Bus, and the class that needs to handle this event must subscribe to the Bus. Using this system can greatly reduce the coupling between modules.

To implement the bus of this system, I used the library Otto developed by Square. I declare two buses. One (REST_BUS) is used to implement direct communication between usecase and REST APIs, and the other (UI_BUS) sends events to the presentation layer. Among them, REST_BUS will use any available thread to process the event, while UI_BUS will only send the event to the default thread, that is, 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 this module, and you can also use this module to operate the bus.

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

Finally, let's think about this situation: when a user opens an application, the most popular movies will first be displayed.

WhenonCreateWhen the method is called, presenter subscribes to UI_BUS to listen for events. Then, the presenter will executeGetMoviesUseCaseTo initiate a request. Presenter willonStopCancels 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);}

To receive events, the presenter must implement a method. The parameters of this method must be consistent with those of the events sent to the bus. And this method must be annotated@SubsribeTagging

@Subscribe@Overridepublic void onPopularMoviesReceived(PopularMoviesApiResponse popularMovies) {    popularMoviesView.hideLoading();    popularMoviesView.showMovies(popularMovies.getResults());}
Reference
  • Architecting Android... The clean way? -Fernando Cejas Chinese Link
  • Proactive 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's summary

The author of this project also summarized a set of templates based on several famous Android architectures. In terms of architecture and subcontracting, it is in line with my idea Android architecture practice (I)-core ideas, which are much simpler than a complete set of processes and more suitable for small teams (1-3 individuals) development.

The difference is that this project uses the event bus to implement inter-module communication. Compared with RxJava, the event bus is easy to understand. However, the fault of the event bus is that the dependency is weak, that is, you cannot easily find out who initiated the event. This effect can be understood as low coupling, or "lost" during maintenance. Therefore, I prefer RxJava's design pattern.

There are two subsequent chapters on this project, mainly about Material Design and its compatibility. It is not particularly profound, but if you need the same UI effect, you can refer to it and I will translate it for your convenience.

Related Article

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.