Best practices in Android Development

Best practices in Android Development

Android is currently the most used OS across the world. The popularity of Android applications is at a pick. As a developer, our duty is to provide applications with the best performance and innovative features.

To achieve this, the developer must follow certain standards in the application development process. In this article, you will find some useful tips and rules for developing an Android application.

Development Tool and Android SDK

Use the Google-recommended Android Studio as your development tool. It is very fast and improved than other tools like Eclipse etc. Place your Android studio and SDK in the same directory to avoid reinstalls of components and make sure that the location has all the admin (read/write) permissions to avoid issues.

Build System

The default option must be Gradle using the Android-provided Gradle plugin.

It’s important to define the application’s build process in Gradle files, rather than being reliant on IDE-specific configurations. This is helpful for consistent builds between tools and better support for continuous integration systems of your projects.

In a project structure, Gradle offers a large degree of flexibility in your project structure, unless you have a compelling reason to do otherwise, you should accept its default structure as that simplifies your build scripts.

MinSdkVersion: 21. Please check Android version charts before deciding on the minimum API for a project. There are different statistics for different regions. It is important to mention that some material design features are available on Android 5.0 (API level 21) and above. Hence, from API 21, the multidex support library is not needed anymore.

In Place of (shell, Python, Perl, etc) scripts, you can make tasks in Gradle. Just follow Gradle’s documentation for more details. Google is providing many helpful Gradle recipes, specific to Android.

Product Flavours

Product flavor is a very good feature provided by Google. This would be very helpful when you have different versions for different users. For example, if you are a free and paid version or a different version for admin and normal users. Instead of providing conditions inside the code, use the product flavor feature in the application.

Code Re-Usability

This is a very important topic in the context of Java code files and XML files. There must be many API calls in the application to achieve different functionalities.

Instead of writing each code every time, make some generalized classes for API calls and with the help of interfaces, use them across the applications. Two main benefits of using this are reduction of time and any further modification in code will be very easy.

Use the <include/> tag in the XML (design) file to reuse layouts in different activities and fragments. For example, to create the same header and footer for each screen, create save, yes, no, and cancel button styles for while application.

Resources

The application includes many static strings. Define all strings in one place called “String.xml”. This can help at the time of localizations (when application will be made for more than one language). Make a different values folder for each language, which you need to support in the application. Make sure to add strings in string files with better naming conventions. Below is an example:

Bad

<string name="error">Api error.</string>

<string name="failed">Load failed.</string>

<string name="list_load_error">List loading failed.</string>

Good

<string name="error_msg_api">Api error.</string>

<string name="error_msg_load">Load failed.</string>

<string name="error_msg_list">List loading failed.</string>

For margins and paddings, “dimens.xml” must be used.

Just like colors.xml, use dimens.xml. Also, add a “palette” of spacing and font sizes, below is an example of a dimens file:

<resources>

<!-- font sizes -->

<dimen name="fontlarger">26sp</dimen>

<dimen name="fontlarge">22sp</dimen>

<dimen name="fontregular">17sp</dimen>

<dimen name="fontsmall">13sp</dimen>


<!-- typical spacing between two views -->

<dimen name="spacinghuge">48dp</dimen>

<dimen name="spacinglarge">22dp</dimen>

<dimen name="spacingnormal">15dp</dimen>

<dimen name="spacingsmall">11dp</dimen>

<dimen name="spacingtiny">6dp</dimen>


<!-- typical sizes of views -->

<dimen name="button_hgt_tall">75dp</dimen>

<dimen name="button_hgt_normal">55dp</dimen>

<dimen name="button_hgt_short">35dp</dimen>

Application Icon

Add application icons in the mipmap folder instead of drawable folders. At the time of building applications for different resolutions, drawable icons will be stripped.

Application Images

Android provides very good drawable folder structures (Like hdpi-drawable, xhdpi-drawable, xxhdpi-drawable, xxxhdpi-drawable) for adding images for multiple resolutions. You need to add some images or icons in the respective folders according to their resolutions. Below are the screen sizes listed with the respective drawable folder.

hdpi – 480*800

xhdpi – 720*1280

xxhdpi – 1080*1920

xxxhdpi – 1440*2560

Although android provides a very good facility for storing or adding icons and images for different resolutions, we just need to use shapes and selector files instead of adding images for every design element. This will help us to reduce application size and faster performance.

Layout Design

To improve application speed, avoid deep-level hierarchy inside the layout. A deep level of hierarchy of views will directly affect UI speed and smoothness. Try to use Relativelayout instead of LinearLayout. Below is a very good example:

Scenario 1: Using Linear Layout

<LinearLayout

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:orientation="horizontal">

<ImageView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/magnifying_glass" />

<LinearLayout

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:orientation="vertical">

<TextView

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="top text" />

<TextView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="bottom text" />

</LinearLayout>

</LinearLayout>

Scenario 2: Using Relative Layout

<RelativeLayout

android:layout_width="wrap_content"

android:layout_height="wrap_content">

<ImageView

android:id="@+id/imageStar"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/magnifyingGlass" />

<TextView

android:id="@+id/txt1"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_toRightOf="@id/ imageStar "

android:text="Lorem ipsom" />

<TextView

android:id="@+id/txt2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@id/txt1"

android:layout_toRightOf="@id/ imageStar "

android:text="lorem ipsom" />

</RelativeLayout>

android:layout_width="wrap_content"

android:layout_height="wrap_content">

<ImageView

android:id="@+id/imageStar"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/magnifyingGlass" />

<TextView

android:id="@+id/txt1"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_toRightOf="@id/ imageStar "

android:text="Lorem ipsom" />

<TextView

android:id="@+id/txt2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@id/txt1"

android:layout_toRightOf="@id/ imageStar "

android:text="lorem ipsom" />

</RelativeLayout>

The second example will be preferable over the first one.

Another very good introduction to layout design is constrained layout. Try to use as much as possible. Constrain layout gives the best performance when we are making apps for different resolutions.

Use External Libraries

Many open-source and free external libraries are available online. Some of them are very optimized and powerful. The developer needs to use this when it’s required. Below are powerful libraries, which will be very helpful.

For Network/API calls: Volley, Retrofit

Parsing JSON response: GSON

Load image from server/lazy loading: Picasso, Glide

Dependency Injection: Dagger2

View Injection: Butterknife

Chart integration: Mpchart

Analytics: Firebase

Google Play service is also a very good library from Google but remember, don’t add a whole play service package. Just add packages, which you want to use.

Proguard Configuration

ProGuard is helpful in applications to shrink the packaged code.

It is configured Gradle to use ProGuard when building a release APK. Below is an example:

buildTypes {

debug {

minifyEnabled false

}

release {

signingConfig signingConfigs.release

minifyEnabled true

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

}

}

In order to determine which code has to be preserved and which code can be discarded or obfuscated, you have to specify one or more entry points to your code. Entry points are classes with main methods, activities, midlets, applets, etc. Android is using the default configuration, which can be found from SDK_HOME/tools/proguard/proguard-android.txt. Using the above details, custom project-specific ProGuard rules, as defined in my-project/app/proguard-rules.pro, will be appended to the default configuration.

A major problem related to ProGuard is to see the application crashing on start with ClassNotFoundException or NoSuchFieldException or similar, even if the build command (i.e. assembly release) is succeeded. This means one of two things:

ProGuard removed the class, enum, method, field or annotation, considering it is not required.

ProGuard renamed the class, enum or field name, but it is being used indirectly by its original name, i.e. through Java reflection.

Pay Attention to app/build/outputs/proguard/release/usage.txt to see if the object in question has been removed or not. Pay Attention to app/build/outputs/proguard/release/mapping.txt to see if the object in question has been obfuscated or not.

To prevent ProGuard from stripping away will need classes or class members, add keep options to your ProGuard config:

-keep class com.futurice.project.MyClass { *; }

Prevent ProGuard from class members or obfuscating classes, add keep names:

-keepnames class com.futurice.project.MyClass { *; }

Content Providers

When we need to store a large amount of data, SharedPreferences are not enough, we need to use platform-standard content providers, which are fast and process-safe.

The problem with ContentProviders is the amount of boilerplate code that is needed to set them up, as well as low-quality tutorials. We cannot find good content or blogs on the internet.

It is possible, however, to generate the ContentProvider by using a library such as Schematic, which significantly reduces the effort.

The other option is database Sqlite with creates tables and columns. It is possible to serialize the data objects, for instance with Gson, and only persist the resulting string.

In this way file a file-based data storage system, you lose performance but on the other hand, you do not need to declare a column for all the fields of the data class.

Memory Leaks

LeakCanary is a very good external library that makes runtime/live detection and identification of memory leaks a more routine part of your application development process. Just remember to configure only the “no-op” dependency in your release build. To make applications optimized for battery consumption, this is the best library to include in our project.

Important Small Points!

  • Use parseable class instead of serializable at the time of sending data in bundles
  • Use AsyncLoader instead of Asynctask
  • Don’t perform heavy tasks on the main thread
  • Use intent service instead of service where it’s possible
  • Use Expresso for unit testing