Android OS has several releases over the past 2 years. These updates have introduced astonishing features thus causing several significant functionalities to become deprecated. This technological evolution has led to Android development challenge of keeping an app compatible with the different levels of Android OS, while keeping UI and UX elegant.
Throughout this tutorial, You will learn about how you can implement UI, UX, code quality, security, and third party libraries, along with tips and tricks to boost the quality of application with minimal efforts.
The following guide will give you an instant notion about the basic android development terminologies in simplest terms, that is being used throughout this tutorial.
View
represents a graphical rectangular on the screen. Every GUI component like Button, TextView, EditText are inherited from View
class.ViewGroup: A ViewGroup
is a layout container, which is responsible for positioning multiple views on the screen. There are various decedents of ViewGroup like LinearLayout
, RelativeLayout
, ConstraintLayout
etc, to position child views in linear or relative fashion.
Activity
is a single screen view that is visible to user. An application can consist multiple Activities for separate functionalities, for e.g splash, Login , signUp etc.1// To create activity, a class must extend Activity or AppCompatActivity class
2 // AppCompatActivity is used to support ActionBar and design features for older version
3public class MainActivity extends AppCompatActivity {
4
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 // static view for MainActivity
9 setContentView(R.layout.activity_main);
10 }
11}
Using a backward compatibility component from a support package requires additional dependencies, which will result in increasing the APK size.
Layout XML file: XML is a tag based file which represents a static layout design view, which can be embedded into activities. A layout file can be attached to an Activity by calling setContentView(int)
method.
A single XML file can be attached with multiple activities and there are many types of XML files, to design menu, shapes, selectors or to store global constant values.**
The design can also be created at run time (while the app is running) using Java or Kotlin code. This is helpful when you have no idea about the number of views to be drawn on the screen in dynamic environment.
Application: An application is a single entity which represents the whole app. It is the first instance to be initialized by Android OS, so often being used to declare global constants or configure services like crash-reposting, analysis, dependency injections which are required to run the app.
You can provide your own implementation by creating a subclass and specifying the fully-qualified name of this subclass as the "android:name" attribute in your AndroidManifest.xml's
1public class MainActivity extends AppCompatActivity {
2
3 // called only once when activity is created
4 // so optimal place to initialize GUI component and services
5 @Override
6 protected void onCreate(Bundle savedInstanceState){...};
7
8 // called everytime when user comes to this activity
9 @Override
10 protected void onStart(){...};
11
12 // called when activity is completely visible
13 @Override
14 protected void onResume(){...};
15
16 // called when activity is partially visible
17 // covered by some dialog
18 @Override
19 protected void onPause(){...};
20
21 // called when current activity is covered by another activity
22 // when user go to next activity
23 protected void onStop(){...};
24
25 // called when activity's object is destroyed and no longer accessible
26 // when user press back-press button
27 @Override
28 protected void onDestroy(){...};
29 }
These methods are invoked in a serial order in normal scenarios. There are many other methods, which can be overridden when required, as shown in below image.
Context : A context
is a special object which is used to access the resources and files (assets, XML constants) contained in application. Activities has their own context and can be used as YourActivityName.this
which is internally initialized by Application object.
getContext()
will give current host activity's context and getApplicationContext()
will give the context of the application. These methods are not accessible in normal classes but they can be passed as values.
Manifest : manifest.xml
contains information about app which is required by android OS to grant permission to access resources like storage, Internet, SMS and registered activities etc. Every activity or customize application class (if there is any) should be registered in manifest.xml
.
A boilerplate manifest file
1<?xml version="1.0" encoding="utf-8"?>
2<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.pavneet.android.boost">
4
5 <!--needs to be added to get access to Internet -->
6 <uses-permission android:name="android.permission.INTERNET"/>
7
8 <application
9 <!--app icon-->
10 android:icon="@mipmap/ic_launcher"
11 <!--app name-->
12 android:label="@string/app_name"
13 <!--aa-->
14 android:roundIcon="@mipmap/ic_launcher_round"
15 <!--support for right to left languages-->
16 android:supportsRtl="true"
17 <!--XML based theme file-->
18 android:theme="@style/AppTheme">
19
20 <!--Register Activity, declare this activity as launcher using intent-filter
21 mean first activity to be opened, on click of app icon-->
22 <activity android:name=".MainActivity">
23 <intent-filter>
24 <action android:name="android.intent.action.MAIN" />
25
26 <category android:name="android.intent.category.LAUNCHER" />
27 </intent-filter>
28 </activity>
29
30 <activity android:name=".AnotherDefaultActivityYetToBeCreated"/>
31
32 </application>
33
34 </manifest>
Gradle: The build system used to download dependencies, tools and to manage application configuration settings to build project.
R.java: A final
Java class file that consists of static final int
constants and array constants. Every file or unique id (+@id/name attribute of views), is given an int
value by the gradle and these constants are used to access those components and files in project.
app\generated\source\r\debug\your_package_name\R.java
directory and should never be modified by hand.findViewById()
takes in an R.id
value based on the component to be selected, such as R.id.my_button
.An Android application should provide a simplified, engaging interface with meaningful motion like elevation, ripple, and material design.
Android 5.0 Lollipop introduced the concept of Material design, which can also be implemented on older versions by using the Android Design library which provides material design components to make an elegant app.
Steps to include design library as dependency
build.gradle
(module)Add the following dependency inside the dependencies
block
1compile 'com.android.support:design:27.0.2'
or use implementation
for Android studio 3.0. Note that the version number 27.0.2
may differ in to future releases:
1implementation 'com.android.support:design:27.0.2'
A FloatingActionButton
(fab) is a round button with an icon, which denotes a quick primary action on the interface such as:
Snackbar appears from the bottom for a short time then disappears. It shows a brief message along with an action button to perform corresponding task. Using the SnackBar is best when trying to:
If fab button is at the bottom of the screen, you can coordinate with the SnackBar to move the fab up when the SnackBar appears. This is done by using coordinator
layout as the root ViewGroup.
FoatingAndSnakBarActivity.Java
1package com.pavneet.android.boost;
2
3import android.os.Bundle;
4import android.support.design.widget.FloatingActionButton;
5import android.support.design.widget.Snackbar;
6import android.support.v7.app.AppCompatActivity;
7import android.support.v7.widget.Toolbar;
8import android.view.View;
9
10public class FoatingAndSnakBarActivity extends AppCompatActivity {
11
12 @Override
13 protected void onCreate(Bundle savedInstanceState) {
14 super.onCreate(savedInstanceState);
15 setContentView(R.layout.activity_foating_and_snak_bar);
16
17 FloatingActionButton fab = findViewById(R.id.fab);
18 fab.setOnClickListener(new View.OnClickListener() {
19 @Override
20 public void onClick(View view) {
21 Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
22 .setAction("Action", new View.OnClickListener() {
23 @Override
24 public void onClick(View view) {
25 // sncakbar button clicked
26 }
27 }).show();
28 }
29 });
30 }
31}
By default the width of SnakBar is same as screen, so
view
here should be a child of your ViewGroup to retrieve the width internally.
activity_foating_and_snak_bar.xml
1<?xml version="1.0" encoding="utf-8"?>
2<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 tools:context="com.pavneet.android.boost.FoatingAndSnakBarActivity">
8
9
10 <android.support.design.widget.FloatingActionButton
11 android:id="@+id/fab"
12 android:layout_width="wrap_content"
13 android:layout_height="wrap_content"
14 android:layout_gravity="bottom|end"
15 android:layout_margin="@dimen/fab_margin"
16 app:srcCompat="@android:drawable/ic_dialog_email" />
17
18</android.support.design.widget.CoordinatorLayout>
Tip: Design library provides many other elegant views like NavigationDrawer
, CollapsingToolbarLayout
.
TextInputLayout
is like an EditText
which supports floating label as hint and it moves up when user stats typing.
1<android.support.design.widget.TextInputLayout
2 android:layout_width="match_parent"
3 android:layout_height="wrap_content">
4
5 <android.support.design.widget.TextInputEditText
6 android:layout_width="match_parent"
7 android:layout_height="wrap_content"
8 android:hint="@string/form_username"/>
9
10</android.support.design.widget.TextInputLayout>
Android supports variety of animations which can be created via Java and XML as well.
1startActivity(new Intent(YourCurrentActivity.this,DestinationActivity.class));
2// animate by applying fade in and fade out animations
3overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
Material design standards are the design guidelines for an application's user interface, appearance, and motion. Features of material themes are as follows:
1// fetch the image as bitmap
2Bitmap b= BitmapFactory.decodeResource(getResources(),R.drawable.norml);
3// create a rounded drawable
4RoundedBitmapDrawable drawable= RoundedBitmapDrawableFactory.create(getResources(),b);
5// create a circular image
6drawable.setCircular(true);
Serialization is the process of converting your object into bytes to persist them. This can be achieved by implementing both the Serializable
and Parcelable
interfaces.
The important difference is that Parcelable
is implemented via the Android native (C++) framework which requires less resources per single instruction resulting in overall better performance. Serializable
is best when sending singular objects from one activity to another. Parcelable is far better for larger transfers, however, such as sending lists of customized objects to the next Activity
. Learn more about the difference here.
Like every system, the Android OS has limited resources, so it's always better to avoid using large size bitmaps or images. There are other options that be applied, such as
To achieve better performance for simple layout(without multiple nested ViewGroups), it is preferred to use LinearLayout due to support of linear flow-based UI drawing whereas the Relative layout always use two measure passes.
LinearLayout is also quite handy for allocating the available width or height as per the weight
property.
weight
property, 0dp
of space (either height or width) will be allocated.1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout android:layout_height="match_parent"
3 android:layout_width="match_parent"
4 xmlns:android="http://schemas.android.com/apk/res/android" >
5
6 <View
7 android:background="#c44cd4"
8 android:layout_width="0dp"
9 android:layout_weight="1"
10 android:layout_height="match_parent"/>
11 <View
12 android:layout_weight="1"
13 android:background="#7bf2dc"
14 android:layout_width="0dp"
15 android:layout_height="match_parent"/>
16</LinearLayout>
Clean-Code Architecture separates the background logic from the UI so that both user interface and background logic can be tested independently.
MVP: Model View Presenter is the talk of the town amongst Android developers when it comes to implementing clean-code architecture.
Live template offers quick code insertion shortcut, so you don't have to write the whole statement. Instead just press ctrl+j
and select the Toast
or any other option to insert respective code.
Use shift+f6
to rename components, variables or module across project.
There are lots of other useful options under Refactor
menu like extract, change signature, and more that save us a lot of time and prevent mistakes.
Builder patterns: Builder patterns are widely used to create APIs and libraries and reducing the complexity of and effort needed for object creation.
There are several patterns that have been invented to solve specific problems. These patterns and problems are discussed here. Read more to create better quality applications.
Android studio provides built-in support to test user interface actions via recoding an Espresso test. Espresso tests state expectations, interactions, and assertions.
A simple example would be to perform a button click and check whether the text of TextView has changed or not.
1onView(withId(R.id._button)).perform(click()); // perform click
2onView(withText("Hello")).check(matches(isDisplayed())); // check a view is visible with text "Hello"
To Record a test: Click "run" in menu Select "Record Esprsso Test" This will open the app on a device and record user actions, generating a UI test.
An APK is like an archive. It contains a classes.dex archive which is a collection of .class
files.
Anyone having access to dex2-jar tool can obtain the original source code (java files) and can build a personal version of your market app to harm your product value by uploading a free version of your app.
The process is called Reverse engineering, and it is a major security threat to app revenue.
By default, Android Studio built a debug version of project as an APK, from which the original source code can be easily obtained.
Never share your debug APK with any outside user.
Unfortunately, there is currently no way to protect our app from reverse engineering so the optimal solution is to use obfuscation.
To generate obfuscated code, the apk should be generated as a release version. A release version is signed with a SHA1 key and outputs a working obfuscated source code apk.
1public class MainActivity extends AppCompatActivity
2{
3 private ArrayAdapter<String> adapter;
4 private ListView listView;
5
6 protected void onCreate(Bundle paramBundle)
7 {
8 super.onCreate(paramBundle);
9 setContentView(2130968605);
10 this.listView = ((ListView)findViewById(2131558552));
11 this.adapter = new ArrayAdapter(this, 17367046, Util.DEMO_LIST_ITEMS);
12 this.listView.setAdapter(this.adapter);
13 }
14}
1import android.support.v7.a.a;
2import android.support.v7.a.s;
3import android.support.v7.a.u;
4
5public class MainActivity extends s
6{
7 private ListView i;
8 private ArrayAdapter<String> l;
9
10 protected void onCreate(Bundle paramBundle)
11 {
12 super.onCreate(paramBundle);
13 setContentView(2130968602);
14 this.i = ((ListView)findViewById(2131558552));
15 this.l = new ArrayAdapter(this, 17367046, Util.DEMO_LIST_ITEMS);
16 this.i.setAdapter(this.l);
17 }
18}
Reference
Proguard-rules.pro
This file contains the instructions to obfuscate source code for release apk. ProGuard is a command line tool that shrinks the size of apk by optimizing, obfuscating and eliminating the files (java/bytecode/resources) which results in smaller size apk.
Enable progurad:
1android {
2 compileSdkVersion 26
3 buildToolsVersion "26.0.1"
4 defaultConfig {
5 applicationId "com.pavneet.android.boost"
6 minSdkVersion 15
7 targetSdkVersion 26
8 versionCode 1
9 versionName "1.0"
10 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
11 }
12 buildTypes {
13 debug {
14 minifyEnabled true
15 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
16 }
17 release {
18 minifyEnabled true
19 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 }
21 }
22}
The above configuration is for testing purposes. It will obfuscate the APK for every build. Please do not use the minifyEnabled true
for debug
because it will result in longer project buld duration.
Often you might be required to disable obfuscation for POJO classes and libraries to meet proper naming convention during JSON parsing or placing network calls. To accommodate for this, you can define customize rules for which code to keep.
There is basically no way that you can protect your API key from a hacker but the safest way is to use an NDK, or a Native Developers Toolkit. Through the NDK, corresponding C and C++ functions can be implemented in Android project.
The NDK ports C and C++ code into separate libraries that are hard to decompile — although the NDK compiled code can still be opened with hexadecimal code, it is still hard to detect an API key out of hex code.
Learn more about NDKs and security.
Every Android release introduces new features that might not be backward compatible with older versions, making it important to make your app compatible with older versions. You can put a check to verify the current android OS version and process according as
1if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
2 // current os is marshmallow or above
3}else{/* perform alternative actions for older version */}
Android has a huge open source development community and there are thousands of developers who has published their great work in open source community which saves lot of time and efforts while offering tons of features.
For example, do not use background threads to download and display images just because you can write lengthy code — use Picasso, an image downloading library which offers lot other functionalities like cache, resizing, error handling and easily customizable.
1Picasso.with(context)
2 .load(url)
3 .resize(50, 50)
4 .centerCrop()
5 .into(imageView)
CardView
, RecyclerView
, retrofit etc.swipeToRefresh
, BottomBarNavigation
, and the design library.I am glad that you have made this far! Thanks for reading and I hope this guide helped you with your Android endeavors!