Android Application Development Standards



Android SDK

Place your Android SDK somewhere in your home directory or some other application-independent location. Some distributions of IDEs include the SDK when installed, and may place it under the same directory as the IDE. This can be bad when you need to upgrade (or reinstall) the IDE, as you may lose your SDK installation, forcing a long and tedious redownload.
Also avoid putting the SDK in a system-level directory that might need root permissions, to avoid permissions issues.
Preferred location for a Mac is: /Library/Android/sdk

Build system

Your default option should be Gradle using the Android Gradle plugin.
It is important that your application's build process is defined by your Gradle files, rather than being reliant on IDE specific configurations. This allows for consistent builds between tools and better support for continuous integration systems.

Naming Conventions

Be sure to check out the Ribot Code and Style Guidelines for a more extensive breakdown of suggested style and naming guidelines.

For Java Code

The following naming and casing conventions are important for your Java code:
TYPE
EXAMPLE
DESCRIPTION
Variable
incomeTaxRate
All variables should be camelcase
Constant
DAYS_IN_WEEK
All constants should be all uppercase
Method
convertToEuroDollars
All methods should be camelcase
Parameter
depositAmount
All parameter names should be camelcase


For Android Classes

Android classes should be named with a particular convention that makes their purpose clear in the name. For example all activities should end with Activity as in MoviesActivity. The following are the most important naming conventions:

Name
Convention
Inherits
Activity
CreateTodoItemActivity
AppCompatActivity, Activity
List Adapter
TodoItemsAdapter
BaseAdapter, ArrayAdapter
Database Helper
TodoItemsDbHelper
SQLiteOpenHelper
Network Client
TodoItemsClient
N/A
Fragment
TodoItemDetailFragment
Fragment
Service
FetchTodoItemService
Service, IntentService

Use your best judgement for other types of files. The goal is for any Android-specific classes to be identifiable by the suffix.

Android Folder Structure

There are several best practices for organizing your app's package structure.

Organize packages by category


The way to do this is to group things together by their category. Each component goes to the corresponding package:

com.example.myapp.activities - Contains all activities
com.example.myapp.adapters - Contains all custom adapters
com.example.myapp.models - Contains all our data models
com.example.myapp.network - Contains all networking code
com.example.myapp.fragments - Contains all fragments
com.example.myapp.utils - Contains all helpers supporting code.
com.example.myapp.interfaces - Contains all interfaces

Keeping these folders in each app means that code is logically organized and scanning the code is a pleasant experience.

Organize packages by application features

Alternatively, we can package-by-feature rather than layers. This approach uses packages to reflect the feature set. Consider the following package structure as outlined in this post:

com.example.myapp.service.* - Is a subpackage for all background related service packages/classes
com.example.myapp.ui.* - Is a subpackage for all UI-related packages/classes
com.example.myapp.ui.mainscreen - Contains classes related to some app's Main Screen
com.example.myapp.ui.detailsscreen - Contains classes related to some app's Item Details Screen
This feature allows you to place DetailsActivity, DetailsFragment, DetailsListAdapter, DetailsItemModel in one package, which provides comfortable navigation when you're working on "item details" feature.

DetailsListAdapter and DetailsItemModel classes and/or their properties can be made package-private, and thus not exposed outside of the package. Within the package you may access their properties directly without generating tons of boilerplate "setter" methods.

This can make object creation really simple and intuitive, while objects remain immutable outside the package.

Android Studio as your main IDE

The recommended IDE for Android development is Android Studio because it is developed and constantly updated by Google, has good support for Gradle, contains a range of useful monitoring and analysis tools and is fully tailored for Android development.

Avoid adding Android Studio's specific configuration files, such as .iml files to the version control system as these often contain configurations specific of your local machine, which won't work for your colleagues.

Libraries

Jackson

Jackson is a Java library for JSON serialization and deserialization, it has a wide-scoped and versatile API, supporting various ways of processing JSON: streaming, in-memory tree model, and traditional JSON-POJO data binding.

GSON

Gson is another popular choice and being a smaller library than Jackson, you might prefer it to avoid 65k methods limitation. Also, if you are using Moshi, another of Square's open source libraries, builds upon learnings from the development of Gson and also integrates well with Kotlin.

Networking, caching, and images

There are a couple of battle-proven solutions for performing requests to backend servers, which you should use rather than implementing your own client. We recommend basing your stack around OkHttp for efficient HTTP requests and using Retrofit to provide a typesafe layer. If you choose Retrofit, consider Picasso for loading and caching images.
Retrofit, Picasso and OkHttp are created by the same company, so they complement each other nicely and compatibility issues are uncommon.

RxJava

RxJava is a library for Reactive Programming, in other words, handling asynchronous events. It is a powerful paradigm, but it also has a steep learning curve. We recommend taking some caution before using this library to architect the entire application.
If you have no previous experience with Rx, start by applying it only for responses from app's backend APIs. Alternatively, start by applying it for simple UI event handling, like click events or typing events on a search field. If you are confident in your Rx skills and want to apply it to the whole architecture, then write documentation on all the tricky parts. Keep in mind that another programmer unfamiliar to RxJava might have a very hard time maintaining the project. Do your best to help them understand your code and also Rx.
Use RxAndroid for Android threading support and RxBinding to easily create Observables from existing Android components.

Beware of the dex method limitation, and avoid using many libraries. Android apps, when packaged as a dex file, have a hard limitation of 65536 referenced methods [1] [2] [3]. You will see a fatal error on compilation if you pass the limit. For that reason, use a minimal amount of libraries, and use the dex-method-counts tool to determine which set of libraries can be used in order to stay under the limit. Especially avoid using the Guava library, since it contains over 13k methods.

Activities and Fragments

There is no consensus among the community about how to best organize Android architectures with Fragments and Activities. Square even has a library for building architectures mostly with Views, bypassing the need for Fragments, but this still is not considered a widely recommendable practice in the community.

Because of Android API's history, you can loosely consider Fragments as UI pieces of a screen. In other words, Fragments are normally related to UI. Activities can be loosely considered to be controllers, they are especially important for their lifecycle and for managing state. However, you are likely to see variation in these roles: activities might take UI roles (delivering transitions between screens), and fragments might be used solely as controllers. We suggest you sail carefully, making informed decisions since there are drawbacks for choosing a fragments-only architecture, or activities-only, or views-only. Here is some advice on what to be careful with, but take them with a grain of salt:

Avoid using nested fragments extensively, because matryoshka bugs can occur. Use nested fragments only when it makes sense (for instance, fragments in a horizontally-sliding ViewPager inside a screen-like fragment) or if it's a well-informed decision.
Avoid putting too much code in Activities. Whenever possible, keep them as lightweight containers, existing in your application primarily for the life cycle and other important Android-interfacing APIs. Prefer single-fragment activities instead of plain activities - put UI code into the activity's fragment. This makes it reusable in case you need to change it to reside in a tabbed layout, or in a multi-fragment tablet screen. Avoid having an activity without a corresponding fragment, unless you are making an informed decision.
Java packages structure

We recommend using a feature based package structure for your code. This has the following benefits:
  1. Clearer feature dependency and interface boundaries.
  2. Promotes encapsulation.
  3. Easier to understand the components that define the feature.
  4. Reduces risk of unknowingly modifying unrelated or shared code.
  5. Simpler navigation: most related classes will be in the one package.
  6. Easier to remove a feature.
  7. Simplifies the transition to module based build structure (better build times and Instant Apps support)

The alternative approach of defining your packages by how a feature is built (by placing related Activities, Fragments, Adapters etc in separate packages) can lead to a fragmented code base with less implementation flexibility. Most importantly, it hinders your ability to comprehend your code base in terms of its primary role: to provide features for your app.

Resources

Naming

Follow the convention of prefixing the type, as in type_foo_bar.xml. Examples: fragment_contact_details.xml, view_primary_button.xml, activity_main.xml.

Organizing layout XMLs

If you're unsure how to format a layout XML, the following convention may help.

One attribute per line, indented by 4 spaces
android:id as the first attribute always
android:layout_**** attributes at the top
style attribute at the bottom
Tag closer /> on its own line, to facilitate ordering and adding attributes.
Rather than hard coding android:text, consider using Design time attributes available for Android Studio.

<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical">

   <TextView
       android:id="@+id/name"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_alignParentRight="true"
       android:text="@string/name"
       style="@style/FancyText"/>

   <include layout="@layout/reusable_part" />

</LinearLayout>
As a rule of thumb, attributes android:layout_**** should be defined in the layout XML, while other attributes android:**** should stay in a style XML. This rule has exceptions, but in general works fine. The idea is to keep only layout (positioning, margin, sizing) and content attributes in the layout files, while keeping all appearance details (colors, padding, font) in styles files.

The exceptions are:
android:id should obviously be in the layout files
android:orientation for a LinearLayout normally makes more sense in layout files
android:text should be in layout files because it defines content
Sometimes it will make sense to make a generic style defining android:layout_width and android:layout_height but by default these should appear in the layout files
Use styles. Almost every project needs to properly use styles, because it is very common to have a repeated appearance for a view. At least you should have a common style for most text content in the application, for example:

<style name="ContentText">
   <item name="android:textSize">@dimen/font_normal</item>
   <item name="android:textColor">@color/basic_black</item>
</style>

Applied to TextViews:
<TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@string/price"
   style="@style/ContentText"
   />
You probably will need to do the same for buttons, but don't stop there yet. Go beyond and move a group of related and repeated android:**** attributes to a common style.

Split a large style file into other files. You don't need to have a single styles.xml file. Android SDK supports other files out of the box, there is nothing magical about the name styles, what matters are the XML tags <style> inside the file. Hence you can have files styles.xml, styles_home.xml, styles_item_details.xml, styles_forms.xml. Unlike resource directory names which carry some meaning for the build system, filenames in res/values can be arbitrary.

colors.xml

It is a color palette. There should be nothing else in your colors.xml than just a mapping from a color name to an RGBA value. Do not use it to define RGBA values for different types of buttons.

Don't do this:

<resources>
   <color name="button_foreground">#FFFFFF</color>
   <color name="button_background">#2A91BD</color>
   <color name="comment_background_inactive">#5F5F5F</color>
   <color name="comment_background_active">#939393</color>
   <color name="comment_foreground">#FFFFFF</color>
   <color name="comment_foreground_important">#FF9D2F</color>
   ...
   <color name="comment_shadow">#323232</color>

You can easily start repeating RGBA values in this format, and that makes it complicated to change a basic color if needed. Also, those definitions are related to some context, like "button" or "comment", and should live in a button style, not in colors.xml.

Instead, do this:

<resources>
   <!-- grayscale -->
   <color name="white"     >#FFFFFF</color>
   <color name="gray_light">#DBDBDB</color>
   <color name="gray"      >#939393</color>
   <color name="gray_dark" >#5F5F5F</color>
   <color name="black"     >#323232</color>

   <!-- basic colors -->
   <color name="green">#27D34D</color>
   <color name="blue">#2A91BD</color>
   <color name="orange">#FF9D2F</color>
   <color name="red">#FF432F</color>
</resources>

Ask for this palette from the designer of the application. The names do not need to be color names as "green", "blue", etc. Names such as "brand_primary", "brand_secondary", "brand_negative" are totally acceptable as well. Formatting colors as such will make it easy to change or refactor colors, and also will make it explicit how many different colors are being used. Normally for a aesthetic UI, it is important to reduce the variety of colors being used.

dimens.xml

Treat this like colors.xml. You should also define a "palette" of typical spacing and font sizes, for basically the same purposes as for colors. A good example of a dimens file:

<resources>
   <!-- font sizes -->
   <dimen name="font_larger">22sp</dimen>
   <dimen name="font_large">18sp</dimen>
   <dimen name="font_normal">15sp</dimen>
   <dimen name="font_small">12sp</dimen>

   <!-- typical spacing between two views -->
   <dimen name="spacing_huge">40dp</dimen>
   <dimen name="spacing_large">24dp</dimen>
   <dimen name="spacing_normal">14dp</dimen>
   <dimen name="spacing_small">10dp</dimen>
   <dimen name="spacing_tiny">4dp</dimen>

   <!-- typical sizes of views -->
   <dimen name="button_height_tall">60dp</dimen>
   <dimen name="button_height_normal">40dp</dimen>
   <dimen name="button_height_short">32dp</dimen>
</resources>

You should use the spacing_**** dimensions for layouting, in margins and paddings, instead of hard-coded values, much like strings are normally treated. This will give a consistent look-and-feel, while making it easier to organize and change styles and layouts.

strings.xml

Name your strings with keys that resemble namespaces, and don't be afraid of repeating a value for two or more keys. Languages are complex, so namespaces are necessary to bring context and break ambiguity.

Bad

<string name="network_error">Network error</string>
<string name="call_failed">Call failed</string>
<string name="map_failed">Map loading failed</string>

Good

<string name="error_message_network">Network error</string>
<string name="error_message_call">Call failed</string>
<string name="error_message_map">Map loading failed</string>

Don't write string values in all uppercase. Stick to normal text conventions (e.g., capitalize first character). If you need to display the string in all caps, then do that using for instance the attribute textAllCaps on a TextView.

Bad

<string name="error_message_call">CALL FAILED</string>

Good

<string name="error_message_call">Call failed</string>


Avoid a Deep Hierarchy

Sometimes you might be tempted to just add yet another LinearLayout, to be able to accomplish an arrangement of views. This kind of situation may occur:

<LinearLayout
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   >
   <RelativeLayout
       ...
       >
       <LinearLayout
           ...
           >
           <LinearLayout
               ...
               >
               <LinearLayout
                   ...
                   >
               </LinearLayout>
           </LinearLayout>
       </LinearLayout>
   </RelativeLayout>
</LinearLayout>

Even if you don't witness this explicitly in a layout file, it might end up happening if you are inflating (in Java) views into other views.

A couple of problems may occur. You might experience performance problems, because there is a complex UI tree that the processor needs to handle. Another more serious issue is a possibility of StackOverflowError.

Therefore, try to keep your views hierarchy as flat as possible: learn how to use ConstraintLayout, how to optimize your layouts and to use the <merge> tag.

Beware of problems related to WebViews. When you must display a web page, for instance for a news article, avoid doing client-side processing to clean the HTML, rather ask for a "pure" HTML from the backend programmers. WebViews can also leak memory when they keep a reference to their Activity, instead of being bound to the ApplicationContext. Avoid using a WebView for simple texts or buttons, prefer the platform's widgets.

Test Frameworks

Use JUnit for unit testing Plain, Android dependency-free unit testing on the JVM is best done using Junit.

Avoid Robolectric Prior to the improved support for JUnit in the Android build system, Robolectric was promoted as a test framework seeking to provide tests "disconnected from device" for the sake of development speed. However, testing under Robolectric is inaccurate and incomplete as it works by providing mock implementations of the Android platform, which provides no guarantees of correctness. Instead, use a combination of JVM based unit tests and dedicated on-device integration tests.

Espresso makes writing UI tests easy.

AssertJ-Android an AssertJ extension library making assertions easy in Android tests Assert-J comes modules easier for you to test Android specific components, such as the Android Support, Google Play Services and Appcompat libraries.

A test assertion will look like:

// Example assertion using AssertJ-Android
assertThat(layout).isVisible()
   .isVertical()
   .hasChildCount(5);

Emulators


The performance of the Android SDK emulator, particularly the x86 variant, has improvement markedly in recent years and is now adequate for most day-to-day development scenarios. However, you should not discount the value of ensuring your application behaves correctly on real devices. Of course, testing on all possible devices is not practical, so rather focus your efforts on devices with a large market share and those most relevant to your app.

Data storage

SharedPreferences

If you only need to persist simple values and your application runs in a single process SharedPreferences is probably enough for you. It is a good default option.

There are some situations where SharedPreferences are not suitable:

Performance: Your data is complex or there is a lot of it
Multiple processes accessing the data: You have widgets or remote services that run in their own processes and require synchronized data
Relational data Distinct parts of your data are relational and you want to enforce that those relationships are maintained.
You can also store more complex objects by serializing them to JSON to store them and deserializing them when retrieving. You should consider the tradeoffs when doing this as it may not be particularly performant, nor maintainable.

ContentProviders

In case SharedPreferences are not enough, you should use the platform standard ContentProviders, which are fast and process safe.

The single problem with ContentProviders is the amount of boilerplate code that is needed to set them up, as well as low quality tutorials. It is possible, however, to generate the ContentProvider by using a library such as Schematic, which significantly reduces the effort.

You still need to write some parsing code yourself to read the data objects from the Sqlite columns and vice versa. It is possible to serialize the data objects, for instance with Gson, and only persist the resulting string. In this way you lose in performance but on the other hand you do not need to declare a column for all the fields of the data class.

Comments