Android Concepts

ADB
Android Debug Bridge (adb) is a command-line tool that lets you communicate with a device. The adb command facilitates a variety of device actions, such as installing and debugging apps.

It is a client-server program that includes three components:

  • A client, which sends commands. The client runs on your development machine. You can invoke a client from a command-line terminal by issuing an adb command.
  • A daemon (adbd), which runs commands on a device. The daemon runs as a background process on each device.
  • A server, which manages communication between the client and the daemon. The server runs as a background process on your development machine.


Command to install an APK : adb install path_to_apk
Command to check connected devices : adb devices

Set up port forwarding :
 
sets up forwarding of host port 6100 to device port 7100
adb forward tcp:6100 tcp:7100

sets up forwarding of host port 6100 to local:logd
adb forward tcp:6100 local:logd

Copying the files :
To copy a file or directory and its sub-directories from the device
adb pull remote local

To copy a file or directory and its sub-directories to the device
adb push local remote
Eg : 
adb push foo.txt /sdcard/foo.txt


Launch Modes : 
There are four launch modes for activity. They are:
1. standard
2. singleTop
3. singleTask
4. singleInstance

1. Standard
This is the default launch mode of an activity (If not specified). It creates a new instance of an activity in the task from which it was started. Multiple instances of the activity can be created and multiple instances can be added to the same or different tasks. In other words you can create the same activity multiple times in the same task as well as in different tasks.

<activity android:launchMode=”standard” />

Example:
Suppose you have A, B, C and D activities and your activity B has “launch mode = standard”. Now you again launching activity B –

State of Activity Stack before launch B

A -> B -> C -> D

State of Activity Stack after launch B

A -> B -> C -> D -> B

2. SingleTop
In this launch mode if an instance of activity already exists at the top of the current task, a new instance will not be created and Android system will route the intent information through onNewIntent(). If an instance is not present on top of task then new instance will be created.

Using this launch mode you can create multiple instance of the same activity in the same task or in different tasks only if the same instance does not already exist at the top of stack.

<activity android:launchMode=”singleTop” />

Example:
Case 1:
Suppose you have A, B and C activities and your activity D has “launch mode = singleTop”. Now you launching activity D -

State of Activity Stack before launch D

A -> B -> C

State of Activity Stack after launch D activity

A -> B -> C -> D (Here D launch as usual)

Case 2:
Suppose you have A, B, C and D activities and your activity D has “launch mode = singleTop”. Now you again launching activity D -

State of Activity Stack before launch D

A -> B -> C -> D

State of Activity Stack after launch D activity

A -> B -> C -> D (Here old instance gets called and intent data route through onNewIntent() callback)

3. SingleTask
In this launch mode a new task will always be created and a new instance will be pushed to the task as the root one. If an instance of activity exists on the separate task, a new instance will not be created and Android system routes the intent information through onNewIntent() method. At a time only one instance of activity will exist.

<activity android:launchMode=”singleTask” />

Example:
Case 1:
Suppose you have A, B and C activities and your activity D has “launch mode = singleTask”. Now you launching activity D -

State of Activity Stack before launch D

A -> B -> C

State of Activity Stack after launch D activity

A -> B -> C -> D (Here D launch as usual)

Case 2:
Suppose you have A, B, C and D activities and your activity B has “launch mode = singleTask”. Now you again launching activity B-

State of Activity Stack before launch D

A -> B -> C -> D

State of Activity Stack after launch B activity

A -> B (Here old instance gets called and intent data route through onNewIntent() callback)

Also notice that C and D activities get destroyed here.

4. SingleInstance
This is very special launch mode and only used in the applications that has only one activity. It is similar to singleTask except that no other activities will be created in the same task. Any other activity started from here will create in a new task.

<activity android:launchMode=”singleInstance” />

Example:
Case 1:
Suppose you have A, B and C activities and your activity D has “launch mode = singleInstance”. Now you launching activity D -

State of Activity Stack before launch D

A -> B -> C

State of Activity Stack after launch D activity

Task1 — A -> B -> C

Task2 — D (here D will be in different task)

Now if you continue this and start E and D then Stack will look like-

Task1 — A -> B -> C -> E

Task2 — D

Case 2:
Suppose you have A, B, C activities in one task and activity D is in another task with “launch mode = singleInstance”. Now you again launching activity D-

State of Activity Stack before launch D

Task1 — A -> B -> C

Task2 — D

State of Activity Stack after launch B activity

Task1 — A -> B -> C

Task2 — D (Here old instance gets called and intent data route through onNewIntent() callback)

Intent Flags

Android also provides Activity flags by which you can change the default behavior of Activity association with Tasks while starting it via startActivity() method. These flags values can be pass through Intent extra data.

FLAG_ACTIVITY_NEW_TASK

This flag works similar to “launchMode = singleTask”.

FLAG_ACTIVITY_CLEAR_TASK

This flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. The activity becomes the new root of an otherwise empty task, and any old activities are finished.

FLAG_ACTIVITY_SINGLE_TOP

This flag works similar to “launchMode = singleTop”.

FLAG_ACTIVITY_CLEAR_TOP

If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.


Different Types of Request Permissions

The three permission protection levels in Android are as follows:

  1. Normal Permissions
  2. Signature Permissions
  3. Dangerous Permissions

1: Normal Permissions

Normal Permission is like if there is little or no danger to the user’s privacy. For example, if we want to acquire the Network State, these things do not need any user privacy, and we do not need to ask the user to use Network State in this situation. We may utilize this feature directly by adding permission to the AndroidManifest.xml file. The system will automatically provide authorization to your app during the installation process. Normal Permissions include the following permissions:

  1. ACCESS_LOCATION_EXTRA_COMMANDS
  2. ACCESS_NETWORK_STATE
  3. CHANGE_NETWORK_STATE
  4. ACCESS_WIFI_STATE
  5. CHANGE_WIFI_STATE
  6. CHANGE_WIFI_MULTICAST_STATE
  7. BLUETOOTH
  8. BLUETOOTH_ADMIN
  9. INTERNET
  10. SET_ALARM
  11. SET_WALLPAPER
  12. VIBRATE
  13. WAKE_LOCK

2: Signature Authorization

The Android system gives these rights during installation, but there is a catch. The app requesting permission must be signed with the same signature as the app defining the needed permission.  Some of the Signature permissions are as follows:

  1. BIND_ACCESSIBILITY_SERVICE
  2. BIND_AUTOFILL_SERVICE
  3. BIND_CARRIER_SERVICE
  4. BIND_DEVICE_ADMIN
  5. BIND_INPUT_METHOD
  6. BIND_NFC_SERVICE
  7. BIND_TV_INPUT
  8. BIND_WALLPAPER
  9. READ_VOICEMAIL
  10. WRITE_SETTINGS
  11. WRITE_VOICEMAIL

3: The dangerous ones

Permissions that are dangerous include those that affect user data in some way. For example, if we wish to read contacts from the phone or access the phone’s file storage, these rights fall under the Dangerous category since they involve the user’s privacy. To utilize Dangerous permissions, we must first seek permission by displaying an alert dialogue or any other dialogue. If the user refuses the permission, our application will be unable to utilize that permission. Some of the Dangerous permissions are as follows:

  1. READ_CALENDAR
  2. WRITE_CALENDAR
  3. CAMERA
  4. READ_CALL_LOG
  5. WRITE_CALL_LOG
  6. READ_CONTACTS
  7. WRITE_CONTACTS
  8. GET_ACCOUNTS
  9. ACCESS_FINE_LOCATION
  10. ACCESS_COARSE_LOCATION
  11. SEND_SMS
  12. RECEIVE_SMS
Intent Filters

An intent filter is an expression in an app's manifest file that specifies the type of intents that the component would like to receive.

When we create an implicit intent, the Android system finds the appropriate component to start by comparing the contents of the intent to the intent filters which is declared in the manifest file of other apps on the device. If the intent matches an intent filter, the system starts that component and delivers the Intent object to it

  • Implicit intent uses the intent filter to serve the user request.
  • The intent filter specifies the types of intents that an activity, service, or broadcast receiver can respond.
  • Intent filters are declared in the Android manifest file.
  • Intent filter must contain <action>

Most of the intent filter are describe by its 

  1. <action>, 
  2. <category> and
  3. <data>

Compile SDK and Target SDK
The compile sdk version is the version of Android that the build tools uses to compile and build the application in order to release, run, or debug.
The target sdk version is the version of Android that your app was created to run on.

DEX
A DEX file is an executable file saved in a format that contains compiled code written for Android. It is referred to as a "Dalvik Executable," and can be interpreted by the Dalvik virtual machine

Context
This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes

In which Thread will a service run when declared in the Manifest File?
A service will always run in its hosting process.
If we start a service from a Activity, that service will run on the main thread blocking the UI and leads to ANR.
To avoid it, we should make use of background threads like Coroutines

Memory Leaks : 
We should not use Activity Context, instead we should use ApplicationContext cos Activities are likely to be leaked. We should avoid Long-Lived references to Activities i.e AsyncTask.
Use LeakCanary which is a memory leak detection library for android
Avoid Non Static inner classes in Activities. Use inner static classes with weak references so they cant be garbage collected when they are not used.


Design Patterns

A Design Pattern is a general, reusable solution to a commonly occurring problem within a given context.

Builder pattern
In a builder pattern, you are only concerned about what you need from a class and not everything that a class has. 
When we have a model class and that class is having a number of parameter out of which some are important and some are not important then we can use the Builder pattern. By using the Builder pattern, the user need not call all the methods(as in the case of constructors) present in the class. The user can call only the required methods and even the order of calling of the method is not fixed i.e you can call any method before and after any method

Singleton pattern
There are cases when you need only one instance of a class. So, whenever you call the object of the class, then the new object should not be created(only one-time object creation will be there). This design pattern provides a global point of access to a class. For example, the network connection in an application should be done once and not every time because it is a very expensive process. So in these cases, we can use a singleton.

Dependency Injection pattern
in the Dependency Injection pattern, we provide the dependency of a class from outside the class and no dependency will be provided in the same class.
 if a class "DataManager" is dependent on "DatabaseHelper" and "NetworkHelper" then we should not provide these two dependencies in the same "DataManager" class because there may be cases when these two dependencies are the dependencies of some other classes also. So, if there is a change in these dependencies, then you have to change the code of these two dependencies in all the classes that are dependent on these two.

Adapter pattern
An Adapter is something like a connector that is used to connect two or more incompatible interface. This pattern lets the classes work together.

Pending Intent
It basically provides the third party application with permission to execute a particular piece of code that we specify. More frequently used in NotificationManager, AlarmManager
So it starts at some point in the future whereas Intent starts immediately
Android PendingIntent is an object that wraps up an 
intent object and it specifies an action to be taken place in future. In other words, PendingIntent lets us pass a future Intent to another application and allow that application to execute that Intent as if it had the same permissions as our application, whether or not our application is still around when the Intent is eventually invoked.

A PendingIntent is generally used in cases were an AlarmManager needs to be executed or for Notification. A PendingIntent provides a means for applications to work, even after their process exits.

PendingIntent uses the following methods to handle the different types of intents:

  • PendingIntent.getActivity() : Retrieve a PendingIntent to start an Activity
  • PendingIntent.getBroadcast() : Retrieve a PendingIntent to perform a Broadcast
  • PendingIntent.getService() : Retrieve a PendingIntent to start a Service

An example implementation of PendingIntent is given below.
Intent intent = new Intent(this, SomeActivity.class);

// Creating a pending intent and wrapping our intent
PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
try {
// Perform the operation associated with our pendingIntent
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
The operation associated with the pendingIntent is executed using the send() method.

The parameters inside the getActivity() method and there usages are described below :

this (context) : This is the context in which the PendingIntent starts the activity
requestCode : “1” is the private request code for the sender used in the above example. 
Using it later with the same method again will get back the same pending intent. 
Then we can do various things like cancelling the pending intent with cancel(), etc.
intent : Explicit intent object of the activity to be launched
flag : One of the PendingIntent flag that we’ve used in the above example is FLAG_UPDATE_CURRENT. 
This one states that if a previous PendingIntent already exists, then the current one will update it with the latest intent. 
There are many other flags like FLAG_CANCEL_CURRENT etc.

Retrieve a PendingIntent to start a new Activity(s)/Broadcast/Service:
PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags)
PendingIntent.getActivities(Context context, int requestCode, Intent[] intents, int flags)
PendingIntent.getBroadcast(Context context, int requestCode, Intent intent, int flags)
PendingIntent.getService(Context context, int requestCode, Intent intent, int flags)
Flags
FLAG_CANCEL_CURRENT - If the described PendingIntent already exists, the current one should 
be canceled before generating a new one.
FLAG_NO_CREATE - If the described PendingIntent does not already exist, then simply return null instead of creating it.
FLAG_ONE_SHOT - PendingIntent can be used only once.
FLAG_UPDATE_CURRENT - If the described PendingIntent already exists, then keep it but replace its 
extra data with what is in this new Intent.
FLAG_IMMUTABLE - PendingIntent should be immutable. It means that the additional intent argument passed to the send methods to fill in unpopulated properties of this intent will be ignored

Constraint Layout
Constraint Layout simplifies the creation of large and complex layouts. The main advantage of Constraint Layout is that it helps to create a flat view hierarchy. A flat view hierarchy is very beneficial in the case of performance analysis. We can say that Constraint Layout is the combination of the Relative and Linear layout
No nested view groups like inside RelativeLayout or LinearLayout etc. You can make Responsive UI for android using ConstraintLayout and its more flexible compare to RelativeLayout

How ConstraintLayout differs from RelativeLayout? 

  • In Constraint Layout, we have to add constraints to the view on all four sides whereas in Relative Layout we can simply align our UI component relative to its ID using the ids of UI components.
  • In Relative Layout, the UI which is actually seen in the Design editor of Android Studio will be the same as that we will get to see in the app, but in the case of Constraint layout if the UI component is not Constrained then the UI will not look same as that of in design editor.

How ConstraintLayout differs from Linear Layout? 

  • With the help of ConstraintLayout, we can position our UI components in any sort of order whether it may be horizontal or vertical. But in the case of Linear Layout, we can only arrange our UI components either in a horizontal or in a vertical manner.
  • Linear Layout provides usability with which we can equally divide all the UI components in a horizontal or vertical manner using weight sum but in Constraint Layout, we have to arrange this UI component manually.
  • In Linear Layout the UI which is actually seen in the Design editor of Android Studio will be the same as that we will get to see in the app, but in the case of Constraint layout if the UI component is not Constrained then the UI will not look the same as that of in design editor.

Advantages : 
  • To make handling complex screen designs easier
  • To improve the performance of complex layouts
  • Drag and drop GUI builder

Disadvantages of using ConstraintLayout 

  • When we use the Constraint Layout in our app, the XML code generated becomes a bit difficult to understand.
  • In most of the cases, the result obtain will not be the same as we got to see in the design editor.
  • Sometimes we have to create a separate layout file for handling the UI for the landscape mode.
dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
}
Few Constraint Layout components :
Aspect Ratio
Guide Line
Barrier
Group
Chains

Parcelable :
Parcelable is an Android only Interface used to serialize a class so its properties can be transferred from one activity to another.
The Parcelable interface adds methods to all classes you want to be able to transfer between activities. These methods deconstructs the object in one activity and reconstructs it in another.

Creating the Property Class

First create a class to hold info about each property. Start by adding the following into a new class file in your project.
The below class contains a series of properties, getter functions and a constructor to create a single object of the class.

public class Property implements {
//property basics
private int streetNumber;
private String streetName;
private String suburb;
private String state;
private String description;
private String image;
private Double price;
private int bedrooms;
private int bathrooms;
private int carspots;
private Boolean featured;

//main constructor
public Property(int streetNumber, String streetName, String suburb, String state, String description, Double price, String image, int bedrooms, int bathrooms, int carspots, Boolean featured){

this.streetNumber = streetNumber;
this.streetName = streetName;
this.suburb = suburb;
this.state = state;
this.description = description;
this.price = price;
this.image = image;
this.bedrooms = bedrooms;
this.bathrooms = bathrooms;
this.carspots = carspots;
this.featured = featured;
}


//getters
public int getStreetNumber() { return streetNumber; }
public String getStreetName() {return streetName; }
public String getSuburb() {return suburb; }
public String getState() {return state; }
public String getDescription() {return description; }
public Double getPrice() {return price; }
public String getImage() { return image; }
public int getBedrooms(){ return bedrooms; }
public int getBathrooms(){ return bathrooms; }
public int getCarspots(){ return carspots; }
public Boolean getFeatured(){return featured; }
}

Adding the Parcelable Interface
Here’s the main part, implementing the interface. Change the declaration of the class as follows:

public class Property implements Parcelable {
//write object values to parcel for storage
public void writeToParcel(Parcel dest, int flags){
//write all properties to the parcle
}

//constructor used for parcel
public Property(Parcel parcel){
//read and set saved values from parcel
}

//creator - used when un-parceling our parcle (creating the object)
public static final Parcelable.Creator<Property> CREATOR = new Parcelable.Creator<Property>(){

@Override
public Property createFromParcel(Parcel parcel) {
return new Property(parcel);
}

@Override
public Property[] newArray(int size) {
return new Property[0];
}
};

//return hashcode of object
public int describeContents() {
return hashCode();
}
}

Parcelable needs this code to function. It handles the process of copying your object data into a parcel for transmission between activities and then re-creating the object on the other side.

Writing Method – writeToParcel

In this method we add all our class properties to the parcel in preparation for transfer. We use each of the write methods to add each of our properties.

//write object values to parcel for storage
public void writeToParcel(Parcel dest, int flags){
dest.writeString(streetName);
dest.writeString(suburb);
dest.writeString(state);
dest.writeString(description);
dest.writeString(image);
dest.writeInt(streetNumber);
dest.writeValue(featured);
dest.writeDouble(price);
dest.writeInt(bedrooms);
dest.writeInt(bathrooms);
dest.writeInt(carspots);
}

Notes:

The order in which we write these values is important. When collecting these values later we will need to collect them in the same order.
If we are going to send boolean values (for example the featured property). We will have to use writeValue and then force cast it to a boolean on the other side as there is no native method for adding booleans.

Reading Method – Property

This method is the constructor, called on the receiving activity, where you will be collecting values.

When the secondary activity calls the getParcelableExtra method of the intent object to start the process. This constructor is where you collect the values and set up the properties of the object:

//constructor used for parcel
public Property(Parcel parcel){
streetName = parcel.readString();
suburb = parcel.readString();
state = parcel.readString();
description = parcel.readString();
image = parcel.readString();
streetNumber = parcel.readInt();
featured = (Boolean) parcel.readValue(null);
price = parcel.readDouble();
bedrooms = parcel.readInt();
bathrooms = parcel.readInt();
carspots = parcel.readInt();
}

At this point you’ve populated the object with data.

If you are using your own object then the name of this function will match the name of your own class e.g personanimalplace, the name has to match the class name.

The Creator Method

Parcelable requires this method to bind everything together. There’s little you need to do here as the createFromParcel method will return your newly populated object.

//used when un-parceling our parcel (creating the object)
public static final Parcelable.Creator<Property> CREATOR = new Parcelable.Creator<Property>(){

@Override
public Property createFromParcel(Parcel parcel) {
return new Property(parcel);
}

@Override
public Property[] newArray(int size) {
return new Property[0];
}
};

Passing the data through intent

Intent intent = new Intent(MainActivity.this, DetailActivity.class);
intent.putExtra("Property", property);
startActivity(intent);

Collecting Values in the Secondary Activity
//collect our intent
Intent intent = getIntent();
Property property = intent.getParcelableExtra("Property");

//now collect all property values
String streetName = property.getStreetName();
Integer streetNumber = property.getStreetNumber();
String suburb = property.getSuburb();
String state = property.getState();
String description = property.getDescription();
Double price = property.getPrice();
Integer bedrooms = property.getBedrooms();
Integer bathrooms = property.getBathrooms();
Integer carspots = property.getCarspots();
String image = property.getImage();
Integer imageID = this.getResources().getIdentifier(image, "drawable", this.getPackageName());
String address = streetNumber + " " + streetName + ", " + suburb + ", " + state;

Difference between Serializable and Parcelable

Serializable

Serializable is a markable interface or we can call as empty interface. It doesn’t have any pre-implemented methods. Serializable is going to convert object to byte stream. So user can pass the data between one activity to another activity. The main advantage of serializable is creation and passing data is very easy but it is a slow process compare to parcelable.

import java.io.Serializable;
class serializableObject implements Serializable {
String name;
public serializableObject(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

Parcelable

Parcel able is faster than serializable. Parcel able is going to convert object to byte stream and pass the data between two activities. Writing parcel able code is little bit complex compare to serialization. It doesn’t create more temp objects while passing the data between two activities.

import android.os.Parcel;
import android.os.Parcelable;
class parcleObject implements Parcelable {
private String name;
protected parcleObject(Parcel in) {
this.name = in.readString();
}
public parcleObject(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static final Creator<parcleObject> CREATOR = new Creator<parcleObject>() {
@Override
public parcleObject createFromParcel(Parcel in) {
return new parcleObject(in);
}
@Override
public parcleObject[] newArray(int size) {
return new parcleObject[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
}
}

Conclusion : 

  1. Parcelable is faster than Serializable interface
  2. Parcelable interface takes more time to implement compared to Serializable interface
  3. Serializable interface is easier to implement
  4. Serializable interface creates a lot of temporary objects and causes quite a bit of garbage collection
  5. Parcelable array can be passed via Intent in android










Comments

Popular posts from this blog

Android - Using KeyStore to encrypt and decrypt the data

Stack and Queue

Java Reflection API