Modern Android Application Architecture & Development: Part 1 – Tools & Libraries

In continuation to our series of posts with our friends on the Nordstrom Technology team we’re going to take a detour from RxJava and start looking at modern application architecture.

Introduction

Android development has changed significantly since we first started developing applications circa 2009.  Typically the build system was Ant, (Maven if you were adventurous and really wanted package management), the IDE was Eclipse and the language was of course Java.  The emulator was, until only recently, laughably bad. Android library support was still evolving. Simple tasks like talking to a JSON backend and presenting data was painful.

public class MainActivity extends Activity {

    private TextView responseText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);
        responseText.findViewBy(R.id.responseText);
        // call AsynTask to perform network operation on separate thread
        new HttpAsyncTask().execute("http://api.stackexchange.com/v2.2/questions?site=stackoverflow");
    }

    public static String GET(String url) {

        InputStream inputStream = null;
        String result = "";

        try {
            // create HttpClient
            HttpClient httpclient = new DefaultHttpClient();

            // make GET request to the given URL
            HttpResponse httpResponse = httpclient.execute(new HttpGet(url));

            // receive response as inputStream
            inputStream = httpResponse.getEntity().getContent();

            // convert inputstream to string
            if (inputStream != null)
                result = convertInputStreamToString(inputStream);
        }
        catch (Exception e) {
            Log.d("InputStream", e.getLocalizedMessage());
        }

        return result;
    }

    private static String convertInputStreamToString(InputStream inputStream) throws IOException {

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line = "";
        String result = "";

        while ((line = bufferedReader.readLine()) != null)
            result += line;

        inputStream.close();

        return result;

    }

    private class HttpAsyncTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... urls) {
            return GET(urls[0]);
        }

        // onPostExecute displays the results of the AsyncTask.
        @Override
        protected void onPostExecute(String result) {

            Toast.makeText(getBaseContext(), "Received!", Toast.LENGTH_LONG).show();
            textView.setText(result);
        }
    }
}

Who remembers, and who still does, a GET request like this?

It’s huge and we haven’t even marshalled the data into objects yet!  Fortunately things have been evolving especially after Google introduced Android Studio and Gradle as their defacto environment. Libraries have made our lives infinitely easier and tooling has gotten significantly better. However, a lot of projects are still being built as if it was five years ago. Now I don’t blame developers for this.  Android, unlike iOS, has a ton of options to choose from, and there is often no clear direction from Google.  Even some of Google’s own libraries; Volley, a solution for Async networking, for example; are poorly advertised.

Android often feels it is plagued by JQuery syndrome.  There are  a thousand ways to do something, but what works best?  In this series of blog posts we’ll build a real life application that uses what we feel is the best architecture/technology to achieve robust and well made apps.  We’ll focus on building a pretty typical client server application piece by piece.

In Part 1 we’ll discuss the basics of our Android architecture and the libraries we use to build our applications.  If you’re unfamiliar with what’s out there, or what’s being used, give it a read.  If you want to dive straight into the implementation then start with Part 2: Architecture Basics, Project Organization and Clean Code (Coming soon!)

IDE’s, Languages & Build Systems

As previously mentioned Android Studio and Gradle are now the recommended development environment for Android. If you’re still considering using Eclipse for a new project it’s unsupported. Frankly it’s time to get used to Android Studio.

Java is still the dominant development language on android. Though it’s completely possible to build an app using different JVM languages for example: Groovy, Kotlin etc. The New York Times app for example is based on RxJava and Groovy:

Getting Groovy With Reactive Android

We would still recommend sticking to Java due to the wealth of information currently out there. In our project we’ll slowly migrate to use RetroLambda to reduce the verbosity of our code.

Having a build server such as Jenkins will make managing builds in any environment that much simpler. A good alternative is Travis if you don’t want to spin up your own infrastructure.

Android Versions

What Android versions should you support? It’s pretty safe to no longer support anything Ice Cream Sandwich (4.0) and below. Version statistics are always available on the Android Developers Site.

Android Version Statistics

There were significant changes between 2.x and 4.x SDK levels. Android Studio now provides you with an easy guide on what features are supported on project creation. Google has done a nice job offering backward compatibility libraries to support older devices as well. More on that:

http://developer.android.com/tools/support-library/index.html

Emulators

Having a good emulator is essential for rapid development, reducing build times and testing on different device configurations. Previously the Android default emulator was so poor that most developers just used physical devices. Google has finally released a decent emulator utilizing Intel’s HAXM technology. While it’s gotten better, we currently recommend Genymotion. Genymotion is fast, really fast. It’s free for personal development and simulates the most popular phones on the market today.

Libraries

Play Services

Chances are you will use Google Play Services somewhere within your app. Using Google Play services is an easy way to leverage Google’s other product offerings. The most popular are of course Google Maps and Google Wallet, however it supports a host of others (Wearables, Google Fit, Drive, Places etc). Keep in mind each individual component may be included separately:

Ex: compile ‘com.google.android.gms:play-services:7.0.0’ (All Google services)

or

compile ‘com.google.android.gms:play-services-fitness:7.3.0’ (Google Fit)
compile ‘com.google.android.gms:play-services-wearable:7.3.0’ (Wearables)

Material Design

Material design was introduced with Lollipop last year. It’s an attempt to unify look and feel of apps on the Android platform. The entire design guide can be found here:

http://www.google.com/design/spec/material-design/introduction.html#introduction-principles

It’s worthwhile to get yourself up to speed on Material Design and its principals. Any apps not adhering to the new Material Design will not be getting much love in the Play Store.

Why is this section under libraries? Well, Google, for whatever reason gave us some components and not others. While there is a library for the new card view from Google, something like the floating action button is missing (Update: this is now part of the support libraries). Open source alternatives are needed until Google officially supports its components. We’ll dive into these components more later. Below is a megalist of Android libraries and a lot of material design libraries are highlighted:

https://github.com/snowdream/awesome-android#Material

Networking

Talking with Restful backends is how most apps communicate with servers. The common data retrieval use case

1) User Needs Data
2) Asynchronous Call is Made
3) Data is Requested
4) Return JSON is Marshalled into Objects
5) Data is Presented to the User

Let’s take each individual step:

User Needs Data

Typically triggered by a user action (sign in button, displaying a list) We always break out the service layer apart from the view layer. Projects get ugly quickly when the view layer and service layers are intermixed. We’ll create a separate Android library to accomplish this. When a user needs to perform any action against our Restful backend we’ll call into the service layer.

Asynchronous Call is Made

Not blocking the Android UI thread is critical to prevent Android from killing your app. Some of the major libraries used for this are Volley, Retrofit and Robospice. Each have their strengths and weaknesses. We chose Retrofit for a few reasons. Syntactically it’s very simple and Retrofit also plays well with RxJava which we’ll use to communicate with the view layer and beyond.

Ex: @GET(“/2.2/questions?order=desc&sort=activity&site=stackoverflow”)
Observable getQuestions();

Part 3: Dependency Injection, RxJava, DAO’s and more! will give a full example of this. Much more on this later.

Data is Requested

Once again there are a lot of alternatives for this. Some typical ones are Google HTTP Client and OkHTTP. We use OkHTTP as it’s also by Square and easily integrates with Retrofit. Note: The Apache HTTP libraries have been deprecated for some time now so stay away from them.

Return JSON is Marshalled into Objects

In order to easily work with our data we want it returned as objects. A lot of projects still do this by hand and it’s painful and error prone. Common libraries to do this are Jackson and GSON. We will use GSON in our project.

Data is Presented to the User

In order to present the data to the user we must get back the requested data in a useful form. Once again Volley, Robospice, Retrofit and various others all support this. We are using RxJava. RxJava is a reactive style of programming that is extremely powerful and solves a lot of problems other libraries do not. RxJava was originally developed for the .NET platform but has been ported to seemingly every language known to man. ReactiveCocoa for iOS is extremely popular.

A common use case:

User Logs In -> Server Must Verify Username / Password -> User’s addresses, credit cards, and list of orders are returned from the server. Managing all these interactions is handled with RxJava in an elegant way. Also more on this later.

Event Bus

An event bus is an easy way to communicate between fragments, activities etc. Android has a default event bus but the most popular is Otto by SquareUp. Event busses are a great way to communicate within the app but can be grossly overused. Used sparingly they solve a whole host of issues and reduce callback hell. We’ll use Otto in small doses.

Image Loading

There are a host of image loading frameworks out there. The most popular include Picasso, Volley, Glide, and Universal Image Loader. Recently Facebook released Fresco. Fresco is a robust image library that uses an image pipeline to efficiently manage memory. This solved a host of memory problems in a recent app we were working on as it was extremely image heavy.

Dependency Injection

Dependency injection helps manage inter-dependencies in the application. The most commons ones are Butterknife, Roboguice and Dagger. We use Roboguice as it’s less complex than Dagger and plays well with Mockito for our unit testing. We are currently investigating Dagger as a viable alternative now that it is supported by Google.

Testing

Testing has traditionally been a pain in Android. More projects than not have no tests at all. Tools often don’t play well together and the Android lifecycle and Context often make testing difficult. Things have improved with better testing integration with Android Studio’s recent releases.

Mocking Data

Mock data is important. It allows you to manipulate data to easily perform varying tests. It also allows you to develop without being dependent on the service layer or making live calls. Common mocking frameworks are Mockito, Powermock and Easymock. For our project we’ll use Mockito as it plays well with Roboguice, RxJava and Espresso.

Unit Testing

We’ll test our business logic using straight, and fast, JUnit tests. The app must be structured in a smart way to truly make this achievable. Typically too much logic happens in Android’s lifecycle methods which makes testing extremely fragile. We’ll create helpers to test our business components.

Integration Testing

Numerous libraries allow for on device integration tests. These tests tend to be slower but are able to test both business logic and UI. The most common ones are Espresso, Robolectric (which is a headless JVM and does not require a device), and Robotium. For our project we’ll use Espresso. We chose Espresso as it’s maintained by Google and has good API’s. We’ve experienced a lot of compatibility problems with Robolectric and Robotium especially with new features added by Google.

As you can see there are lots of choices to architect an Android app. In our case we’re drawing from personal experiences in large scale projects. This is by no means the definitive list of everything. There is always better solutions and things are always changing. We’ll take our selected technologies and begin to build our client in Part 2: Architecture Basics, Project Organization and Clean Code

Thanks for reading. If you have any questions or would like to know more about working with the Nordstrom Technology team feel free to shoot us an email!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s