Monday, November 16, 2015

Whats minimum you can do to detect activity leaks in an Android App ?

Just enable the strict mode. Assuming you are coding at midnight and still want to make sure that there are no lingering activity leaks in your app , you think its too much to force a heap dump and analyze that in MAT / JHAT , well here comes the StrictMode to your rescue.

 if (BuildConfig.DEBUG) {  
   StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()  
       .detectAll()  
       .penaltyLog()  
       .build()); 
   StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()  
       .detectAll()  
       .penaltyLog()  
       .penaltyDeathOnNetwork()  
       .build());  
 }   

It totally came to me as a surprise but yeh its true and its awesome

Stack

com.cricket.material E/StrictMode: 
class com.cricket.material.cricket.Summary.LiveScoreSummaryDetail; 
instances=2; limit=1 
com.cricket.material E/StrictMode: 
android.os.StrictMode$InstanceCountViolation:  
class com.cricket.material.cricket.Summary.LiveScoreSummaryDetail;  
instances=2; limit=1
com.cricket.material E/StrictMode: 
at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

Explanation :

Take a look at  StrictMode
/**
2324 If this is a instance count violation, the number of instances in memory,
2325 else -1.
2326 */
2327 public long numInstances = -1;

2188 Returns an object that is used to track instances of activites.
2189 The activity should store a reference to the tracker object in one of 
     its fields.
2190 * @hide
2191 */
2192 public static Object trackActivity(Object instance) {
2193       return new InstanceTracker(instance);
2194}

Note:

Please take this opportunity to understand other useful features of StrictMode
  • NetworkOnMainThread exception

Sunday, November 15, 2015

Don't override the default constructor of a fragment.

You should not override the default empty constructors of fragments, the reason for that is framework recreates fragments accross orientation change using the deafault constructor and any initialization that you do in non default constructor will be lost

But to really experiment about what happens , try to override the constructor and cause an orientation change , you will see that most likely you will hit a null pointer exception if you have passed an object to fragment constructor and tried to access the same after orientation change

This below is an ideal way to use fragment
  /**  
    * Use this factory method to create a new instance of  
    * this fragment using the provided parameters.  
    *  
    * @param param1 Parameter 1.  
    * @return A new instance of fragment SquadFragment.  
    */  
   // TODO: Rename and change types and number of parameters  
   public static SquadFragment newInstance(String param1) {  
     SquadFragment fragment = new SquadFragment();  
     Bundle args = new Bundle();  
     args.putString(ARG_PARAM1, param1);  
     fragment.setArguments(args);  
     return fragment;  
   }  
   
   public SquadFragment() {  
     // Required empty public constructor  
   }  
   
   @Override  
   public void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     if (getArguments() != null) {  
       mParam1 = getArguments().getString(ARG_PARAM1);  
     }  
     mSquadAdapter = new SquadRecyclerViewAdapter(mParam1);  
   }  

Saturday, November 14, 2015

Android Services

There are actually two ways to implement a service 
  1. When your class MyService extends from Service 
  2. When your class MyService extends from IntentService

Rule of thumb:

No matter which service you implement , lifecycle methods of the service will be called on main thread aka UI Thread and this is where i have seen too much of confusion where newbies tend to think that all the methods in the service are called on background thread .
Because of this you should not be calling any methods that would essentially be calling any methods which would block your UI thread in lifecycle methods of service 

Things are not that BAD as you think as you might start to wonder about whats the point then...
  • If you implement #1 you have to start a worker thread in onStartCommand()
    • Once started always run in the background
    • We have to manage the life of service ie call Stopself() once the job is done
  @Override  
   public int onStartCommand(Intent intent, int flags, int startId) {  
     Log.i(TAG, "Service onStartCommand " + startId);  
     final int currentId = startId;  
     Runnable r = new Runnable() {  
       public void run() {  
       }  
     };  
     Thread t = new Thread(r);  
     t.start();  
     return Service.START_STICKY;  
   }  

  • If you implement #2 then you are saved from this and the onHandleIntent() method will be actually called on the background thread and you can actually call long running background task on this thread
    • Once the onHandleIntent() is finished the service is automatically stopped
    • Requests are queued if multiple requests are sent at the same time
 
 @Override  
 protected void onHandleIntent(Intent intent) {  
   Log.d(TAG, "#### " + Thread.currentThread().getName());  
   if (intent != null) {  
     final String action = intent.getAction();  
     }  
  }