Friday, February 19, 2016

Sorting & Searching - Update in progress


  • MergeSort
    • Time Complexity: Worse case - O(nLogn)
    • Auxiliary Space: O(n) 
    • Application: Used in External Sorting

Fragment Android - Update In Progress

- Fragment is a small chunk of UI, process its own events and has its own lifecycle
- can be added/ removed in to activity
- Introduced in Honeycomb, but can be used from 1.6 using support library.

Need of Fragments

      - Can combine several fragments in single Activity
      - Fragments can be re-used across several activity
      - Make use of larger screen

- Fragment Lifecycle
- Fragment & Activity combined Lifecycle 

- Adding Fragment in to Activity 
      - XML
      - runtime

- Inter Fragment communication pattern

- Managing fragment in backstack

- Fragments in ViewPager
     - FragmentPagerAdapter
     - FragmentStatePagerAdapter



Android Studio Tips


  • Module build command
    • gradlew build -p moduleA ( moduleA is the module subDirectory name )


Key Shortcuts

CTL + N - go to class
CTL + SHIFT + N - go to file
CTL + ALT+ SHIFT + N - go to symbol
ALT + Right/Left - go to next/previous editor
CTL + F12 - list class variables
SHIFT + F6 - rename
CTL + Y         - delte line
CTL + ALT + M - extract method;
ALT + Delete - safe delete

ADB Commands

adb shell dumpsys meminfo package_name

adb shell ps | findstr -i search_string

adb shell pm list packages -f | findstr -i search_string

adb shell kill -3 PID

adb shell getprop | findstr -i prod

adb shell getprop | findstr -i ex


adb logcat -v time | findstr -i packagetest




apktool.bat d apk_path target_dir


dex2jar.bat apk_path

Tuesday, February 9, 2016

JVM Architecture


Java Thread Lifecycle


Intent & Intent-Filters

Intent
  • Messaging Object
  • Can be used to request an action from another component.
  • Facilitate communication between components in several ways.
use-cases
  • Start an activity.
  • Start a service.
  • Deliver a broadcast.
Intent Types

  1. Explicit intents: Specify the name by component class name. Can be used only to start a component in your own app.
  2. Implicit intents: Specify the general action to be performed, which allows component from other app to handle it.
If the action is compatible with multiple components, the system displays dialog.

Note: Beginning with Android 5.0 (API level 21), the system throws an exception if you call bindService() with an implicit intent.

Building an Intent
  • Intent object carries information that the Android system uses to determine which component to start.
  1. Component Name: Name of the component, Optional for implicit intent but critical for explicit intent.
  2. Action Name : Specifies the generic action to perform.
  3. Data: The URI (a Uri object) that references the data to be acted on and/or the MIME type of that data
  4. Category: Additional information about the kind of component that should handle the intent
  5. Extras: Key-value pairs that carry additional information required to accomplish the requested action.
  6. Flag: flags instruct the Android system how to launch an activity.
Receiving an Implicit Intent
  • Declare intent filters for each of your app components with an <intent-filter> element in your manifest file.
  • Each intent filter specifies the intent's action, data, and category.
  • The system will deliver an implicit intent to your app component only if the intent can pass through one of your intent filters.
Note: In order to receive implicit intents, you must include the CATEGORY_DEFAULT category in the intent filter. Android automatically applies the the CATEGORY_DEFAULT category to all implicit intents passed to startActivity() and startActivityForResult().

Using a Pending Intent
  • PendingIntent object is a wrapper around an Intent object.
  • Grants permission to other application use the contained Intent as it is executed from your own app process.
Use Case: Notification Manager, Alarm Manager and App Widget executes the intent in app process.

Intent Resolution
- TBU

Painless threading in Android UI

Main or UI thread:
  • in charge of dispatching the events to the appropriate widgets & drawing event.
  • ANR happens if UI thread blocked for more than 5 secs.
  • the Android UI toolkit is not thread-safe and must always be manipulated on the UI thread.
ways to access the UI thread from other threads
  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)
  • Handler
  These methods tend to make your code complicated. Android offers a new utility class, called AsyncTask, that simplifies the creation of long-running tasks that need to communicate with the user interface.

Android Runtime (ART) Feature

Ahead-of-time compilation
    • At install time, ART compiles apps using the on-device dex2oat tool.
              Instead of being JIT, AOT compiles application code (byte) and generates native code in ELF File. Subsequent execution happens from compiled native code (that is ELF)
ELF - Executable and Linkable Format.

Improved garbage collection

  • One GC pause instead of two

Google Cloud Messaging

Google Cloud Messaging for Android (GCM) is a service that allows you to send data from your server to your users' Android-powered device, and also to receive messages from devices on the same connection.






Steps to follow to receive GCM notification in Android Client App

1. Write Broadcast Receiver class which extends WakefulBroadcastReceiver and handle the intent action in onReceive method

Please refer below example

Declare the components in AndroidManifest.xml

<!-- GCM Push Notification -->

<!-- Broadcast Receiver to receive the GCM notification from GCM Agent -->
<receiver
 android:name=".notification.GcmPushNotificationReceiver"
 android:permission="com.google.android.c2dm.permission.SEND" >
 <intent-filter>
  <action android:name="com.google.android.c2dm.intent.RECEIVE" />
 </intent-filter>
</receiver>

<!-- Service to handle in intent action -->
<service android:name="notification.GcmIntentService" >
</service>
<!-- GCM Push Notification -->

GcmPushNotificationReceiver.java

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.util.Log;

public class GcmPushNotificationReceiver extends WakefulBroadcastReceiver {
 
 private static final String TAG = GcmIntentService.class.getSimpleName();

 @Override
 public void onReceive(Context context, Intent intent) {
  if(Debug.DEBUG_LOW) Log.i(TAG, "onReceive action = "+intent.getAction());
     // Explicitly specify that GcmMessageHandler will handle the intent.
        ComponentName comp = new ComponentName(context.getPackageName(),
          GcmIntentService.class.getName());
        
        // Start the service, keeping the device awake while it is launching.
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
 }
}

GcmIntentService.java

import com.google.android.gms.gcm.GoogleCloudMessaging;

import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;


public class GcmIntentService extends IntentService {
 
 private static final String TAG = GcmIntentService.class.getSimpleName();

 public GcmIntentService(String name) {
  super(name);
 }

 @Override
 protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        // The getMessageType() intent parameter must be the intent you received
        // in your BroadcastReceiver.
        String messageType = gcm.getMessageType(intent);
        if(Debug.DEBUG_LOW) Log.i(TAG, "GcmIntentService Received : (" +messageType+")  "+extras.getString("title"));
        
        GcmPushNotificationReceiver.completeWakefulIntent(intent);
 }

}

Customize volley default retry Policy & Cache timeout

Volley Default request retry policy:

/** The default socket timeout in milliseconds */
public static final int DEFAULT_TIMEOUT_MS = 2500;

/** The default number of retries */
public static final int DEFAULT_MAX_RETRIES = 1;

/** The default backoff multiplier */
public static final float DEFAULT_BACKOFF_MULT = 1f;


Volley does retry for you if you have specified the policy. 
Client app can change retry values for each request using below API.

setRetryPolicy(new DefaultRetryPolicy (TIMEOUT_MS, MAX_RETRIES,  BACKOFF_MULT  ));


Example Timeout - 3000 secs, Num of retry - 2, Back Off Multiplier - 2
Attempt 1: 
- time = time + (time * Back Off Multiplier );
- time = 3000 + 6000 = 9000
- Socket Timeout = time;
- Request dispatched with Socket Timeout of 9 Secs
Attempt 2: 
- time = time + (time * Back Off Multiplier );
- time = 9000 + 18000 = 27000
- Socket Timeout = time;
- Request dispatched with Socket Timeout of 27 Secs


Steps to change Volley default Cache Hit & Cache time-out values:

1. Create new Volley Request class.
2. Set custom cacheHit & cacheTimeout values in parseNetworkResponse callback method.

Please refer below example.
GsonRequest.Java
import java.io.UnsupportedEncodingException;
import java.util.Map;

import android.util.Log;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.samsung.android.guardian.utils.Config;

public class GsonRequest<T> extends Request<T> {

 private static final String TAG = GsonRequest.class.getSimpleName();
 private final Gson gson;
 private final Class<T> clazz;
 private final Map<String, String> headers;
 private final Listener<T> listener;
 
 private int cacheHit;
 private int cacheExpiry;

 public GsonRequest(int method, String url, Class<T> clazz,
   Map<String, String> headers, Listener<T> listener,
   ErrorListener errorListener) {
  super(method, url, errorListener);
  
  //Using default volley retry policy
  //If retry policy has to be changed use setRetryPolicy methods from each request objects
  if(Config.VOOLEY_USE_DEFAULT_RETRY_POLICY){
  setRetryPolicy(new DefaultRetryPolicy(
    DefaultRetryPolicy.DEFAULT_TIMEOUT_MS, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
    DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
  }
  GsonBuilder gsonBuilder = new GsonBuilder();

  this.gson = gsonBuilder.create();
  this.clazz = clazz;
  this.headers = headers;
  this.listener = listener;
  
  this.cacheHit = Config.DEFAULT_CACHE_HIT;
  this.cacheExpiry = Config.DEFAULT_CACHE_EXPIRY;
 }
 

 /**
 * @param method - GET/POST/PUT/DELETE
 * @param url - server URL
 * @param clazz - class represents server response
 * @param headers
 * @param listener - listener for success case
 * @param errorListener - listener for failure case
 * @param cacheHit - time milliseconds, after this time cache will be hit, but also refreshed on background.
 *     0 for CacheHit = CacheExpiry case
 * @param cacheExpiry - time milliseconds, after this time cache entry expires completely
 */
 public GsonRequest(int method, String url, Class<T> clazz,
   Map<String, String> headers, Listener<T> listener,
   ErrorListener errorListener, int cacheHit, int cacheExpiry) {
  this(method,url, clazz, headers, listener, errorListener);
  this.cacheHit = cacheHit;
  this.cacheExpiry = cacheExpiry;
 }

 @Override
 public Map<String, String> getHeaders() throws AuthFailureError {
  return headers != null ? headers : super.getHeaders();
 }

 @Override
 protected void deliverResponse(T response) {
  listener.onResponse(response);
 }

 @Override
 protected Response<T> parseNetworkResponse(NetworkResponse response) {
  try {
   String json = new String(response.data,
     HttpHeaderParser.parseCharset(response.headers));
   Log.i(TAG,"parseNetworkResponse data "+json);

   if(Config.VOOLEY_USE_DEFAULT_CACHE_TIMEOUT){
     //Volley default Cache
    return Response.success(gson.fromJson(json, clazz),
      HttpHeaderParser.parseCacheHeaders(response));
   }else{
    // Apply custom cache
    return Response.success(gson.fromJson(json, clazz),
      HttpHeaderParser.parseIgnoreCacheHeaders(response, cacheHit, cacheExpiry));
   }
  } catch (UnsupportedEncodingException e) {
   return Response.error(new ParseError(e));
  } catch (JsonSyntaxException e) {
   return Response.error(new ParseError(e));
  }
 }
}


HttpHeaderParser.java - only new method added
    public static Cache.Entry parseIgnoreCacheHeaders(NetworkResponse response, int cacheHit, int cacheExpiry) {
        long now = System.currentTimeMillis();

        Map<String, String> headers = response.headers;

        long serverDate = 0;

        String serverEtag = null;
        String headerValue;

        headerValue = headers.get("Date");
        if (headerValue != null) {
            serverDate = parseDateAsEpoch(headerValue);
        }

        serverEtag = headers.get("ETag");
        
        final long ttl = now + cacheExpiry;
        
        final long softExpire;
        if(cacheHit > 0){
         softExpire = now + cacheHit;
        }else{
         softExpire = ttl;
        }
        
        Log.i(TAG, "parseIgnoreCacheHeaders softExpire: "+softExpire+", ttl:"+ttl);

        Cache.Entry entry = new Cache.Entry();
        entry.data = response.data;
        entry.etag = serverEtag;
        entry.softTtl = softExpire;
        entry.ttl = ttl;
        entry.serverDate = serverDate;
        entry.responseHeaders = headers;

        return entry;
    }

AsyncTask

  • Allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
  • Should ideally be used for short operations. (use java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask for long running thread).
  • Define 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
  • Async Task uses ThreadPoolExecutor to run multiple tasks at same time. total thread size = CPU Count * 2 + 1.
  • AsyncTask must be subclassed to be used. 
  • The task instance must be created on the UI thread.
  • AsyncTask callback methods are thread safe.
Generic Types.
AsyncTask<Params, Progress, Result>

params....
execute(params....)  (ex: execute(url1, url2, url3))
  • params are passed to doInBackground method which is being executed in worker thread
Progress....
publishProgress(Progress...) 
  • being called inside doInBackground, Progress... value passed to method onProgressUpdate running in UI Thread.
result.....
  • return result.... return value from doInBackground passed to onPostExecute
Cancelling a Task.
isCancelled() 
  • returns true is task been cancelled using API cancel(boolean) 
Execution.
  • Before DONUT - no thread pool in AsyncTask
  • After DONUT - Thread Pool introduced and by default task are executed in multiple thread.
  • After HONECOMP - by default tasks are being executed in single thread to avoid error. use executeOnExecutor(Executor exec, Params... params) API to enable true parallel execution.
  • AsyncTask has two static Executor instance SERIAL_EXECUTOR & THREAD_POOL_EXECUTOR

Java concurrency

  • The use of synchronized methods or statements provides lock acquisition and release to occur in a block-structured way.
  • Lock interface enables lock to be acquired and released in different scopes, and allowing multiple locks to be acquired and released in any order.
Locks
         The Lock interface provides more extensive locking operations than it's possible to obtain via synchronized methods and statements
methods:
  • void lock()
  • void lockInterruptibly()
  • Condition newCondition()
  • boolean tryLock()
  • boolean tryLock(long time, TimeUnit unit)
  • void unlock()
ReentrantLock implements Lock:
  • ReentrantLock(boolean fair) - creates a reentrant lock with the given fairness policy. Passing true to fair results in a lock that uses a fair ordering policy, which means that under contention, the lock favors granting access to the longest-waiting thread.
  • int getHoldCount()
  • boolean isFair()
  • boolean isHeldByCurrentThread()
ReentrantReadWriteLock implements ReadWriteLock
Condition: Where Lock replaces synchronized methods and statements, Condition replaces Object monitor methods.
additionaly having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. 

Atomic variables
  • Contended synchronization is expensive and throughput suffers as a result.A major reason for the expense is the frequent context switching that takes place; a context switch operation can take many processor cycles to complete.
  • volatile variables only solve the visibility problem
The compare-and-swap (CAS) instruction is an uninterruptible instruction that reads a memory location, compares the read value with an expected value, and stores a new value in the memory location when the read value matches the expected value. Otherwise, nothing is done.

java.util.concurrent.atomic offers classes for Boolean (AtomicBoolean), integer (AtomicInteger), long integer (AtomicLong) and reference (AtomicReference) types.
-----------------
  • Java Synchronization protects data corruption on race conditions.
Poor way to achieve synchronization.
  1. spin lock (Busy wait) - overhead.
  2. Sleep lock - Context switching overhead.
ReentrantLock   
  • re-entrant mutual exclusion lock that extends the built-in monitor lock capabilities.
  • Low overhead than ReentrantReadWriteLock
ReentrantReadWriteLock    
  • improves performance when resource more often read than write.
  • Provides more parallelism on multi core or multi processor hardware
Semaphore
  • A non-negative integer that controls the access of multiple threads to a limited number of shared resources.
ConditionObject  
  • Block thread until some conditions becomes true.
CountDownLatch  
  • Allow one or more thread to wait until s set of operation being performed in other threads complete.

ConditionObject(uses sleep locks) & Semaphore(uses busy waiting) big overhead than ReentrantLock&ReentrantReadWriteLock

Semaphore & ConditionObject are flexible and provides more capability. 
------------------
reference ( javaworld )

Sqlite


  • Open Source database
  • supports relational database features like SQL syntax, transactions
  • requires limited memory (approx. 250 KByte) which makes it a light weight database to embed in to each process
  • supports the data types TEXT, INTEGER and REAL

Features:

  • SQLite library and thus becomes an integral part of the application program.
  • Due to the server-less design, SQLite applications require less configuration than client-server databases.
  • SQLite is called zero-conf.
  • The SQLite file format is cross-platform. A database file written on one machine can be copied to and used on a different machine with a different architecture.
  • Adding new tables or new columns to existing tables is so easy.
  • Content can be accessed and updated using powerful SQL queries.
  • SQLite read operations can be multitasked, though writes can only be performed sequentially.

Design Tips:
First, Second and Third normal forms in Database (Students record)
1st - Remove duplicate data and break data in granular level
2nd - All column data should depend on full primar key and not part
3rd - No column should depend on other column

( ref : https://www.youtube.com/watch?v=wp0N1tYjEWc&feature=youtu.be&hd=1)

String Algorithms

Sorting
  1. Key indexed counting
  2. LSD (Least-significant-digit-first) string sorting
    • Sorts equal length strings.
    • uses key index counting method.
  3. MSD (Most-significant-digit-first) string sorting
    • Recurvise sort
    • Sorst any length strings
  4. 3-way radix sort
String Search
  1. R-way Tries
Sub String Searching
  1. Knuth–Morris–Pratt ( Ref YouTube, GitHub )
    • Runtime complexity - O(m + n) where m is length of text and n is length of pattern
    • Space complexity - O(n)
  2. Boyer–Moore
  3. Robin–Karp

Friday, February 5, 2016

Android Performance

Battery Historian

            1. Download Battery Historian from Github ( https://github.com/google/battery-historian)
            2. from Terminal
                       - execute adb shell dumpsys batterystats --reset


Memory Monitor
           1. In-built tool in android studio
           

Heap Viewer


Android Performance Case Study ( Source )

Android Adapter Good Practice ( Source )

Android String Placeholders ( Source )

StrictMode 

Wednesday, February 3, 2016

Displaying Bitmaps Efficiently

Loading Large Bitmaps Efficiently
- Read Bitmap Dimensions and Type
    • BitmapFactory ( decodeByteArray(), decodeFile(), decodeResource(), etc.)
    • BitmapFactory.Options - Setting the inJustDecodeBounds property to true while decoding avoids memory allocation
- Load a Scaled Down Version into Memory
    • it’s not worth loading a higher pixel image into memory if it will eventually be displayed in a lower pixel thumbnail 
    • BitmapFactory.Options - use inSampleSize, To tell the decoder to subsample the image, loading a smaller version into memory
Processing Bitmaps Off the UI Thread
- Use an AsyncTask
        - Handle Concurrency ( when Bitmap is used in ListView, GridView )

Caching Bitmaps

  1. Use a Memory Cache ( fast-loading UI can use memory and disk cache to quickly reload processed images )
    • The LruCache class is well suited for Bitmap cacheing
    • Keeps recently referenced objects in a strong referenced LinkedHashMap
    • Evicts the least recently used member when cache memory exceeds its designated size.


Reference

1. developer.android.com
2. android-developers.blogspot ( Multithreading For Performance )