"Reprint" Android app architecture

Source: Internet
Author: User
Tags sqlite database eventbus

Note: This blog post is reproduced in Http://my.oschina.net/mengshuai/blog/541314?fromerr=z8tDxWUH

This article describes the author of the article in the development of Android applications for several years, experienced 2 architectural changes, the first integration of the Rxjava second integration of the MVP, and the Rxjava with the MVP perfect combination, achieve a low-coupling, code simple, testing a convenient architecture.

In fact, we also encountered in the development, Android entry threshold is lower, if the early on the app planning is not clear, coder to the future change grasp not, technical architecture experience is not strong, the final result is an activity thousands of lines, which wrote a large number of private methods, Split into a few fragment, packaged out a few classes are unable to solve, the result is to see the activity uncomfortable to die, tangled, look at the uncomfortable change is not not change is not, seriously affect the mood of the person to see. And complaining that this is product personnel planning app is not good, no forward-looking, change to change to ...

This article is about using the new structure to solve the problem.

Android App Architecture

Android Application Architecture

Our journey from standard activities and asynctasks to a modern mvp-based architecture powered by RxJava.

The main purpose of this article is to describe how traditional activities and asynctasks patterns can be overdone to the current mainstream MVP architecture based responsive programming framework.

Different parts of a software codebase should be independent, yet perfectly work together like a well-oiled machine?—? phot O by Chester Alvarez.

Enjoy the first: ~ ~ ~ If the loose coupling architecture, the division of labor is clear, then the perfect combination of work is a very hanging thing.
(Turn a picture also to write to understand who took, the copyright consciousness is really strong)

The Android dev ecosystem moves very quickly. Every week new tools is created, libraries is updated, blog posts is written and talks is given. If you go to holiday for a month, by the time you come back there'll be a new version of the support library and/or Play Services.

The ecosystem of Android has changed very quickly in recent years, from the underlying Android API to the application layer of various open source class libraries, tools update very quickly. I fell behind when I was not careful.

I ' ve been making Android apps with the Ribot team for over three years. During this time, the architecture and technologies we've used to build Android apps has been continuously evolving. This article'll take your through this journey by explaining our learnings, mistakes and the reasoning behind these Archi Tectural changes.

I have worked in the Ribot team for more than three years in Android application development, with the continuous innovation of the company's technology, accumulated a lot of experience, errors and the story behind the technology selection.

The Old application architecture

The old Times
Codebases used to follow a basic structure. We didn ' t use no networking library and Asynctasks were still our friends. The diagram below shows approximately how the architecture was.

2012 that time, our code was used by native Android, not using any network request framework, but based on asynctasks writing.
>the code is structured in the Layers:the data layer that is in charge of retrieving/saving data from REST APIs and Persistent data stores; And the view layer, whose responsibility is handling and displaying the data on the UI.
The Apiprovider provides methods to enable activities and fragments to easily interact with the REST API. These methods use URLConnection and asynctasks to perform network calls in a separate thread and return the result to the Activities via callbacks.

The code is divided into two tiers, and the data and view,data layers are primarily used to get the information from the API and save it to the persisted db. The view layer is primarily the data display to the UI. Apiprovider provides methods for easy control and interaction in activity or fragment. Technically, an asynchronous network request is implemented with URLConnection and asynctasks and the result is returned to the callback method called.

In a similar to, the Cacheprovider contains methods that retrieve and store data from Sharedpreferences or a SQLite datab Ase. It also uses callbacks to pass the result back to the activities.

The same principle Cacheprovider provides a series of methods for extracting data from sharedpreferences or SQLite and returning to the activity

Problem

The problems
The main issue with this approach is that the View layer had too many responsibilities. Imagine a simple common scenario where the application have to load a list of blogs posts, cache them in a SQLite database a nd finally display them on a ListView. The Activity would has to do the following:

The main problem is that the view layer has too many cumbersome, with a list of blogs as an example to tell, such as the blog needs to display a ListView, reading data from SQLite, the activity needs to do the following:

  1. Call a method Loadposts (callback) in the Apiprovider
  2. Wait for the Apiprovider success callback and then call Saveposts (callback) in the Cacheprovider.
  3. Wait for the Cacheprovider success callback and then display the posts on the ListView.
  4. Separately handle the potential errors callback from the Apiprovider and Cacheprovider.
    1. Executes the apiprovider inside the Loadposts method, inside the callback parameter content is passed in.
    2. After waiting for the loadposts execution to succeed, execute the Saveposts method in the Cacheprovider inside the callback, and Saveposts also pass in the callback parameter.
    3. After waiting for Saveposts to execute successfully, execute callback inside the method to flush the ListView
    4. Write code to handle the error callback content of 2 32 steps respectively.

This was a very simple example. In a real case scenario the REST API would probably not return the data like the view needs it. Therefore, the Activity'll has to somehow transform or filter the data before showing it. Another common case was when the Loadposts () method takes a parameter that needs to being fetched from somewhere else, for Exa Mple an e-mail address provided by the Play Services SDK. It's likely that the SDK would return the email asynchronously using a callback, meaning that we now has three levels of n ested callbacks. If we keep adding complexity, this approach would result into what is known as callback hell.

This is a relatively simple example, in some real scenarios, the remote API may not return the required value of the program, but the activity must complete the data processing before the results can be displayed. Another example is if the Loadposts method needs to use some other local return parameters, similar to the use of multithreading to achieve synchronous request, in order to ensure that the data normal request, it means that a three-layer callback must be done, if more complex, to understand that these callbacks are very painful things.

In summary:
Activities and fragments become very large and difficult to maintain
Too Many nested callbacks means the code is ugly and difficult to understand so painful to make changes or add new feature S.
Unit testing becomes challenging, if not impossible, because a lot of the logic lives within the activities or fragments t Hat is arduous to unit test.

In short, after a lot of callbacks, activity and fragment are going to die, and the average person can't look straight.

It's a new structure.

A new architecture driven by RxJava
We followed the previous approach for about the years. During that time, we made several improvements that slightly mitigated the problems described above. For example, we added several helper classes to reduce the code in activities and fragments and we started using volley in The Apiprovider. Despite these changes, our application code wasn ' t yet test-friendly and the callback hell issue was still happening too o Ften.

We have been suffering in the structure of egg pain for 2 years, of course, have tried many ways, and ultimately only to alleviate the chaos of the problem. We used the volley in Apiprovider, instead of the asynchttpclient, but actually a hanging sample.

It wasn ' t until when we started reading about RxJava. After trying it in a few sample projects, we realised that this could finally being the solution to the nested callback Probl Em. If you is not a familiar with reactive programming you can read this introduction. In short, RxJava allows-manage data via asynchronous streams and gives you many operators so can apply to the Stream in order to transform, filter or combine the data.

We started Rxjava in less than 2014, and then tried a bunch of simple projects, and the way we felt Rxjava was the ultimate solution to our nested callbacks. Simply put, Rxjava allows you to manage your data through an asynchronous stream, and you can also transform the observable object through the operator (Operators)

Taking into account the pains we experienced in previous years, we started to think on how the architecture of a new AP P would look. So we came up with this.

We've had a few years of experience, and we've got something down here, a new app architecture diagram.

Similar to the first approach, this architecture can is separated into a data and view layer. The data layer contains the DataManager and a set of helpers. The view layer is formed by the Android framework for the like fragments, activities, viewgroups, etc.

Similar to the first method, this architecture is also divided into data layer and view layer, the data layer contains DataManager and a heap of helper;view layer is fragments, activities, viewgroups and so on.

Helper classes (third column on diagram) has very specific responsibilities and implement them in a concise manner. For example, most projects has helpers for accessing REST APIs, reading data from databases or interacting with third par Ty SDKs. Different applications'll has a Different number of helpers but the most common ones is:

Helper is primarily the integration of third-party class libraries, so that in the code a few lines of code can clearly implement a function, such as Request API, access to the database, and so on, although different applications have different class libraries, but they are nothing more than this:

  • Preferenceshelper:reads and saves data in Sharedpreferences.
  • Databasehelper:handles accessing SQLite databases.
  • Retrofit Services:perform calls to REST APIs. We started using Retrofit instead of volley because it provides support for RxJava. It ' s also nicer to use.
    • Read or write data from the Sharedpreferences
    • Read and write SQLite database
    • Similar to square's retrofit service, the HTTP Client, we replaced volley with Restrofit because he supports Rxjava and is more hanging.

Most of the public methods inside helper classes would return RxJava observables.
The DataManager is the brain of the architecture. It extensively uses RxJava operators to combine, filter and transform data retrieved from helper classes. The aim of the DataManager is to reduce the amount's work that activities and fragments has to do by providing data that is the ready-to-display and won ' t usually need any transformation.

Rxjava's core two things are observables (the Observer, the event source) and Subscribers (Observer), the public method in the helper class, will generally return a Rxjava observables;d Atamanager is the entire architecture of the brain, he used a lot of rxjava operators to the helper returned data of the integrated filtering, two times processing.

The code below shows what a DataManager method would look like. This sample method works as follows:

Here's an example to illustrate what DataManager is doing:

  1. Call the Retrofit service to load a list of blogs posts from a REST API
  2. Save the posts in a local database for caching purposes using the Databasehelper.
  3. Filter the blog posts written today because those is the only ones of the view layer wants to display.
    1. Call Retrofit's service and go to the API to request a blog list
    2. Save this data to the database with Databasehelper
    3. Filter out these blogs which are written today and then display to the UI interface.

Components in the view layer such as activities or fragments would simply call this method and subscribe to the returned O Bservable. Once The subscription finishes, the different Posts emitted by the Observable can is directly added to a Adapter in order To is displayed on a recyclerview or similar.

Observables emits a series of events, subscribers (for example, activities or fragments) that handle these events, and can display data directly on some view that can be recycled and reused.
BTW: If a observerble does not have any subscriber, then this observable will not issue any events.

The last element of this architecture is the event bus. The event bus allows us to broadcast events ' happen in the ' data layer, so ' multiple components ' in the view layer C An subscribe to these events. For example, a SignOut () method in the DataManager can post an event when the Observable completes so, multiple Activi Ties that is subscribed to the this event can change the their UI to show a signed out state.

Another module of this architecture is the event Bus,event bus allows us to broadcast (not Android broadcast) on the data layer and then different modules to register and receive different broadcast events

Why is this approach better?
RxJava observables and operators remove the need for have nested callbacks.

Why this way is so awesome, because observables and operators can get rid of that heap of necessary callback methods

The DataManager takes over responsibilities this were previously part of the view layer. Hence, it makes activities and fragments more lightweight.
Moving code from activities and fragments to the DataManager and helpers means that writing unit tests becomes easier.

DataManager replaces much of the code in traditional architectures, making activity and fragment more lightweight. and makes unit testing easier.

Clear separation of responsibilities and have the DataManager as the only point of interaction with the data layer, make S this architecture test-friendly. Helper classes or the DataManager can be easily mocked.

DataManager becomes the only interactive part of the data, so a clear architecture makes it easier to conduct a code self-test.

What problems do we still have?
For large and very complex projects the DataManager can become too bloated and difficult to maintain.
Although view layer such as activities and fragments became more lightweight, they still has to handle a consi Derable amount of logic around managing RxJava subscriptions, analysing errors, etc.

What's the problem with us?
-Datamanger can become very bloated and difficult to maintain for very large and complex projects.
-although activity and fragment have become more lightweight, the handling of error anomalies is to be written in subscriptions places.

An integrated MVP model

Integrating Model View Presenter
In the past year, several architectural patterns such as MVP or MVVM has been gaining popularity within the Android Commu Nity. After exploring these patterns in a sample project and article, we found that MVP could bring very valuable improvements t o Our existing approach. Because Our current architecture is divided in the layers (view and data), adding MVP felt natural. We simply had to add a new layer of presenters and move part of the code from the view to presenters.

A few years ago, many similar MVP and MVVM in some of the Android community is more popular, after research, we found that the MVP model is the most valuable changes to our current program. Our two-tier architecture view-data with the Model-view architecture of MVP and is consistent in concept. We just need to add a presenters layer and then move the code previously implemented in view to the top.

The data layer remains as it is but it's now called model is more consistent with the name of the pattern.
presenters is in charge of loading data from the model and calling the "right" in the view when the result is ready. They subscribe to observables returned by the data manager. Therefore, they has to handle things like schedulers and subscriptions. Moreover, they can analyse error codes or apply extra operations to the data stream if needed. For example, if we need to filter some data and this same filter are not likely to being reused anywhere else, it may make mor E sense to implement it in the presenter rather than in the data manager.

The previous data layer is now the MVP of the Model,presenter is now responsible for loading data from the model, after loading the completion of the call to the left in the activity, ViewGroup in the method. Presenters's subscribe to receive data from observables in Data Manager.
For example, if we need to increase the filtering of the data but not the kind that is needed everywhere, then we can write the code in presenter without writing it in the public datamanager.

Below you can see how a public method in the presenter would look like. This code subscribes to the Observable returned by the Datamanager.loadtodayposts () method we defined in the previous sect Ion.

The datamanager.loadtodayposts () we define will broadcast the data to the corresponding subscribes

The Mmvpview is the view component, this presenter is assisting. Usually the MVP view is a instance of an Activity, Fragment or ViewGroup.

The MVP view does not refer to the Android view, but an instance of the interface component, such as activity, Fragment, ViewGroup, when registering presenter, need to pass in the current instance.

// Activity onCreate 中的代码段 if (presenter == null)        presenter = new Presenter1();        presenter.onTakeView(this);

Like the previous architecture, the "view layer contains standard framework" like viewgroups, fragments or Activi Ties. The main difference is this these components don ' t subscribe directly to observables. They instead implement an Mvpview interface and provide a list of concise methods such as ShowError () or Showprogressindic Ator (). The view components is also in charge of handling user interactions such as click events and act accordingly by calling T The He right method is in the presenter. For example, if we had a button that loads the list of posts, our Activity would call Presenter.loadtodayposts () from the OnClick Listener.

This architecture differs from the previous schema in that Viewlayer, which is the activity, does not subscribe directly to receiving these events from observables. Instead, only in the activity to implement a few simple display errors, show the progress of the method (with the interface interface to standardize the unified), and then the current instance as a parameter to the corresponding event presenter, by presenter to perform these display errors, display the progress of the method.
Of course, the button click events in the user interaction section are handled in the activity.

If you want to see a full working sample of this mvp-based architecture and you can check out our Android boilerplate project On GitHub. You can also read more about it in the Ribot ' s architecture guidelines.

About the MVP article can self-Baidu, MVP Android key words

Why are this approach better?

Why is this the most hanging

  • Activities and fragments become very lightweight. Their only responsibilities is to set up/update the UI and handle user events. Therefore, they become easier to maintain.
  • We can now easily write unit tests for the presenters by mocking the view layer. Before, this code is part of the view layer so we couldn ' t unit test it. The whole architecture becomes very test-friendly.
  • If The data manager is becoming bloated, we can mitigate this problem by moving some code to the presenters.
    • Activity and fragment code is greatly reduced, the logic code is all dropped to presenter, the result is the activity only need to be responsible for UI interactive buttons and other code.
    • For presenter can write separate unit test code, only need to test the method provided by presenter
    • If the datamanager becomes bloated, we can separate the code into the respective presenter.

What problems does we still have?
There's still something left.

Have a single data manager can still is an issue when the codebase becomes very large and complex. We haven ' t reached the point where this was a real problem but we're aware that it could happen.

Only one datamanager is still a problem, especially when the contemporary code project is huge, and of course we have not reached this huge point, even though we know that someday it will happen.

It's important to mention It's not the perfect architecture. In fact, it ' d was naive to think there are a unique and perfect one that would solve all your problems forever. The Android ecosystem would keep evolving at a fast pace and we had to keep up by exploring, reading and experimenting so That's we can find better ways to continue building excellent Android apps.

It's impossible to have a perfect architecture to solve all your problems. TMD Android's entire ecosystem changes too fast, but also the non-standard TM, led us to continue to explore the exploration ... To find a more hanging way to do Android apps.

I hope you enjoyed this article and you found it useful. If So, don ' t forget to click the Recommend button. Also, I ' d love to hear your thoughts on our latest approach.

I hope we can have some suggestions for our latest solution after reading it.

The purpose of this paper is to study new technology in leisure time, write to yourself in popular technical language, and make it easy to consult for future purposes.
Original: Https://medium.com/ribot-labs/android-application-architecture-8b6e34acda65
MVP Introduction: http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0425/2782.html
Rxandroid:https://github.com/reactivex/rxandroid
Eventbus:https://github.com/greenrobot/eventbus

"Reprint" Android app architecture

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.