Sunday, October 28, 2012

Android Service test - callback method not firing

Preface
If you want to execute a long running operation in your program Service is a fine choice. You might ask why not using AsyncTask? The answer to it is simple. AsyncTask is for short operations (few seconds probably) and Service is for longer or more CPU intensive jobs. For better and easier integration, it’s better to test each unit of your program. Android JUnit provides set of classes for writing unit tests. ServiceTestCase is a class by which you can unit test your service class.

Scenario
Consider we have to send some data for a complex calculation to a remote server and wait for the response. We decided to use Service. In our example when user initiates the calculation our service start in the background and send the data to the server. Once the result is back it will update the application local database. Lets have a unit test for our Service.

Problem
Our service is an IntentService and it receives a serviceCallback (ResultReciever). The problem is, before the callback method (onReceiveResult) is called the teardown method of the our unit test terminates the test.

Solution
A solution to this problem could be somehow forcing the main thread to wait for the result of the callBack service method to return. For doing this we can make use of CountDownLatch. This class helps us to pause the thread until one or more operations finishes. Below is the ServiceTestCase utilizing the aforementioned mechanism.

await method of CountDownLatch cause the current thread to wait. When the response is back,  countDown method of CountDownLatch counts down and releases all the waiting threads.


 import java.util.HashMap;  
 import java.util.Map;  
 import java.util.Properties;  
 import java.util.concurrent.CountDownLatch;  
 import android.content.Intent;  
 import android.os.Bundle;  
 import android.os.ResultReceiver;  
 import android.test.ServiceTestCase;  
 public class CalculationServiceTest extends ServiceTestCase<CalculationService>{  
      public CalculationServiceTest() {  
           super(CalculationService.class);  
      }  
      public void testCalculation() throws InterruptedException{  
           //our synchronization aid   
           CountDownLatch signal = new CountDownLatch(1);  
           //passing object for evaluating the result of our service  
           Map<String, String> result = new HashMap<String, String>();  
           //Creating a new thread which is responsible for running our Service  
           new Thread(new WorkerRunnable( signal, result)).start();  
           //casuing the current to wait  
           signal.await();  
           assertEquals(CommunicationConstants.SERVICE_RESULT_SUCCESS, (String)result.get("result"));  
      }  
      class WorkerRunnable implements Runnable {  
           private  CountDownLatch doneSignal;  
           private Map<String, String> result;  
           public WorkerRunnable(CountDownLatch cdl, Map<String, String> result){  
                this.doneSignal = cdl;  
                this.result = result;  
           }  
           @Override  
           public void run() {  
                Intent startServiceIntent = new Intent();  
                startServiceIntent.putExtra(CalculationService.SERVICE_TYPE,  
                          Constant.CALCULATE);  
                ResultReceiver serviceCallback = new ResultReceiver(null) {  
                     @Override  
                     protected void onReceiveResult(int resultCode, Bundle resultData) {  
                          result.put("result", String.valueOf(resultCode));  
                          doneSignal.countDown();  
                     }  
                };  
                //setting a callback for our service  
                startServiceIntent.putExtra(CalculationService.SERVICE_CALLBACK,  
                          serviceCallback);  
                startServiceIntent.setClass(getContext(), CalculationService.class);  
                startService(startServiceIntent);  
           }  
      }  
 }  

Friday, October 19, 2012

Drag & Drop & resize using Ext JS

Preface
If HTML is the structure of a website and CSS its facade which give the look and feel, JavaScript is a vibrant life of it. Incorporating JavaScript is a daunting task and brings whole lots of new difficulties such as cross browser compatibility. Using a framework can mitigate the challenges, provide a mechanism that handles this issue seamlessly and make it much easier to develop and maintain UI reach websites.

Scenario

We want to have the capability of drag and drop in our web page. Suppose we are a photo printing company. A user have uploaded few photos to our website. We show the thumbnail of the uploaded photos on the left side of our page. User can drag and drop thumbnails of the photos they want to have printed to the selectedPanel on the right side of the page. Then, they can resize the each to a bigger size. We distinguish between resize and drag & drop by single and double clicking of the mouse over the desired image thumbnail (div).

Topics covered in this tutorial:
  • Drag & drop
  • Resizer
  • Overriding
  • Dynamically adding/removing CSS classes
  • Iterating an array
  • Distinguishing between single click & double click
  • Query DOM nodes by selectors
Requirement
 Ext JS version 4.1 (This example is using 4.1. You can use other versions but some classes might have changed)

I'm not going to cover the basics of how to incorporate Ext JS. You can have a look at getting started guide and learn the basics and setup.

Consider the snippet below as our photo selection page. All the photos are in pics div and user can drag and drop them to the selectedPics div.
 <html>  
 <head>  
 <link href="ext-all.css" rel="stylesheet" type="text/css">  
 <style type="text/css">  
 .pic {  
   width: 55px;  
   height: 50px;  
   border: 1px solid;  
 }  
 .panel {  
   position: absolute;  
   top: 100px;  
   left: 100px;  
   width: 100px;  
   height: 500px;  
   border: 1px solid;  
 }  
 .selectedPanel {  
   position: absolute;  
   top: 100px;  
   left: 400px;  
   width: 500px;  
   height: 500px;  
   border: 1px solid;  
 }  
 .dropZoneOver {  
   background-color: #99FF99;  
 }  
 .dragStyle {  
   outline: red solid thin;  
 }  
 </style>  
 </head>  
 <body>  
   <div id="pics" class="panel">  
     <div id="pic1" class="pic">Pic1</div>  
     <div id="pic2" class="pic">Pic2</div>  
   </div>  
   <div id="selectedPics" class="selectedPanel"></div>  
 </body>  
 </html>  

Now lets discuss the javascript little bit. You can take a look at the comments in our snippet below for some insight.  In the onReady we are registering event listeners for click and dblClick on all the pic divs (each photo is wrapped in a div). We are differentiating between single click and double click by setting a flag and using a timeout. This distinction is recognized in the fireClickEvent. Before applying either drag and drop or resize  to the thumbnails (divs). We use destroy() method to clean and remove all listeners and destroy the passed object before creating new type of object. By doing these we make sure user's previous operation (either drag and drop or resize) is now canceled, all classes are gone and everything is clean and ready for new operation. 
Resize method gives the resize capability to the received id. Move method give drag and drop capability to all the thumbnails in the pics div. Move method enable drag and drop to the all thumbnails (html div) in the pics div.

For resizing we are using Ext.resizer.Resizer.
For drag and drop we are using Ext.dd.DDProxy.

The code below goes to the head section of our HTML page.

 <script type="text/javascript" src="ext-all-dev.js"></script>  
 <script type="text/javascript">  
   var dragProducts = new Array();  
   var dropTarget;  
   var resizer;  
   var dblClickFlag = false;    
   var clickFlag = true;
   //onReady ensures that all the scripts are loaded then it executes its function  
   Ext.onReady(function(){  
     dragIndex = 0;
     //Add event handler to the element  
     Ext.get('pic1').on('click',function(evt, el, o){  
       startSingleClick(el.id);  
     });  
     Ext.get('pic1').on('dblclick',function(evt, el, o){  
       startDblClick(el.id);  
     });  
     Ext.get('pic2').on('click',function(evt, el, o){  
       startSingleClick(el.id);  
     });  
     Ext.get('pic2').on('dblclick',function(evt, el, o){  
       startDblClick(el.id);  
     });  
   });  
   function startSingleClick(cmpId){  
     clickFlag = true;  
     setTimeout(function() { fireClickEvent(cmpId) }, 500);  
   }  
   function startDblClick(){  
     dblClickFlag = true;  
   }     
   function fireClickEvent(cmpId){  
     if (clickFlag){  
       clickFlag = false;  
       if (dblClickFlag){  
         startResize(cmpId);  
       } else{  
         startMove(cmpId);  
       }  
     }  
     dblClickFlag = false;   
   }      
   function destroy(){  
     if(resizer){  
       Ext.destroy(resizer);  
       resizer = null;  
     }  
     Ext.destroy(dropTarget);    
     Ext.Array.each(dragProducts, function(dragProduct) {  
         Ext.destroy(dragProduct);    
     });  
     dragProducts = new Array();  
   }  
   function resize(cmpId){  
     destroy();  
     var elem = Ext.get(cmpId);  
     var elWidth = elem.getWidth();  
     var elHeight = elem.getHeight();  
     resizer = Ext.create('Ext.resizer.Resizer', {  
       width: elWidth,  
       height: elHeight,  
       el: elem,  
       handles: 'all',  
       pinned: true,  
       dynamic: true    
     });  
   }  
   function move(){  
     var overrides = {  
       onDragEnter : function(evtObj, targetElId) {  
         var targetEl = Ext.get(targetElId);  
         targetEl.addCls('dropZoneOver');  
       },  
       onDragOut : function(evtObj, targetElId) {  
         var targetEl = Ext.get(targetElId);    
         targetEl.removeCls('dropZoneOver');  
       },  
       onDragDrop : function(evtObj, targetElId) {  
         var dragEl = Ext.get(this.getEl());  
         dragEl.removeCls('dragStyle');  
         var dropEl = Ext.get(targetElId);  
          if (dragEl.dom.parentNode.id != targetElId) {  
           dropEl.appendChild(dragEl);  
           this.onDragOut(evtObj, targetElId);  
         }  
       },  
       b4StartDrag : function(x, y) {  
         //Shows a frame while dragging the item  
         this.showFrame(x, y);  
         var dragEl = Ext.get(this.getEl());  
         //adds red border to the dragging item   
         dragEl.addCls('dragStyle');  
       },  
       onInvalidDrop : function() {  
         //indicates an invalid drop. Only related dragDrop objects are valid targets  
         this.invalidDrop = true;  
       },  
       endDrag : function() {  
         //The delete operator removes a property from an object.  
         delete this.invalidDrop;  
       }  
     }  
     destroy();  
     //Query DOM tree for all the elements containing the class "pic"   
     var pics = Ext.query("*[class*=pic]");  
     //Iterate over an array  
     Ext.Array.each(pics, function(pic){  
       dragProducts[dragIndex] = new Ext.dd.DDProxy(pic, 'pic', {  
         isTarget : false  
       });  
       //Apply the overrided functions to the DDProxy class  
       Ext.apply(dragProducts[dragIndex], overrides);  
       dragIndex++;  
     });  
     var sp = Ext.get('selectedPics');  
     //Create valid drop target  
     dropTarget = new Ext.dd.DDTarget(sp, 'pic');  
     }  
   function startResize(cmpId){  
     resize(cmpId);  
   }  
   function startMove(){  
     move();  
   }            
 </script>  

For the details of each class and its properties used in this tutorial please look at  Ext JS documentation. They have a well documented API.

Wednesday, October 3, 2012

Android-memory leak on screen rotation

A practical approach

Preface
Lifecycle of your application is managed by the Android itself. Sometimes you dont have control over when and how the system interrupts your application. Like when screen rotation happens, a call is received, low memory condition or etc. Consequently, you have to proactively handle these occurrences. In this article I want to discuss how you can avoid memory leak when screen orientation happens. All the snippets of code are from my earlier post Location Finder.

Scenario
As you know, long running operations must not be executed on the UI thread. That’s why we have AsyncTask. In my older post Location Finder 1, I have an AsyncTask for querying data from Google Places. Constructor of the RequestHandler class accepts the activity itself. This is because I need to have Context for loading resources and the activity as a call back mechanism to update the UI in the main thread. By passing this reference the Android is not able to garbage collect this activity when screen rotation happens (In case of screen rotation the activity is destroyed and created again) our RequestHandler which is an AsyncTask have a reference to the activity so it wont get garbage collected.

1. There are some design changes since the date of the post.

Possible Approach
Now, lets look at an approach that avoids memory leak. We define 2 methods in our RequestHandler (AsyncTask) as detach and attach. These 2 methods have the responsibility of setting the reference of the activity to null (detaching) and setting back the reference (attaching). When should we detach the activity? We can detach it in the onStop() method as below. You might ask why not detaching in onDestroy() method? Because the system might sometimes kill your app without calling onDestroy(). You can look at the whole code at this address.

Here are part of the codes from each class involved.

GMapActivity: Is the activity class from which the AsyncTask is executed.
TaskComplete: Is a call back interface which our GMapActivity implements.
RequestHandler: Is the AsyncTask responsible for our long running operation.

GMapActivity class:
                                                  .
                                                  .
                                                  .
protected void onStop() {
        //Always call the super first
        super.onStop();
        //This is our AsyncTask detaching.
        if(requestHandler != null){
            requestHandler.detach();
        }
        //This is another class which like our AsyncTask has received a reference of our activity as well.
        //Same mechanism applies here
        if(itemizedoverlay != null){
            itemizedoverlay.detach();
        }
        //you can forget about this line for this example
        locationManager.removeUpdates(this);
        // We dismiss any ProgressDialog. Failing to do so will result in memory leak as well
       // since we have passed the activity to this dialog in onCreate().
        if(queryProgressBar != null){
            queryProgressBar.dismiss();
        }
}
                                                  .
                                                  .
                                                  .
TaskComplete interface:

public interface TaskComplete <T> {
    public void onComplete(T t);
    public void updateProgress(int progress);
}

RequestHandler class:
                                                  .
                                                  .
                                                  .
    //Class level private fields
   //Implemented interface reference
    private TaskComplete <List<OverlayItem>> callBack;
    //Forget about this line for this example
    private String selectedRadius;
    //Forget about this line for this example
    private String pointOfInterest;
   //Context needed for loading resources. No need to worry about this in this example
    private Context context;

public RequestHandler(TaskComplete <List<OverlayItem>> taskComplete, String selectedRadius, String pointOfInterest) {
        this.callBack = taskComplete;
        this.context = ((Activity)callBack).getApplicationContext();
        this.selectedRadius = selectedRadius;
        this.pointOfInterest = pointOfInterest;
    }

     public void detach() {
          callBack = null;
     }

     public void attach(TaskComplete <List<OverlayItem>> taskComplete) {
         this.callBack = taskComplete;
     }

                                                  .
                                                  .
                                                  .
Although we could have defined our task as an inner class I've decided to make it separate. Beware non-static inner classes have an implicit reference to the enclosing class. As a consequence, this reference might prevent the activity from being garbage collected causing memory leak.

Oh, We have detached the activity how about attaching it back. Ok, We want to attach the activity back to the AsyncTask. We said that current activity will be destroyed and recreated again. Before This happens we have to keep a reference to our RequestHandler(AsyncTask). We achieve this by creating a new State class and overriding onRetainNonConfigurationInstance() method in our Activity class. This method returns an object. We return a new instance of State. In this class we put our RequestHandler(AsyncTask) and any other detached objects. This method is called between onStop() and onDestroy(). In onStop() we already detached the activity and now are ready to returning the State of our application.

 public Object onRetainNonConfigurationInstance() {   
        State state = null;
        if(requestHandler != null && itemizedoverlay != null){
            state = new State(requestHandler, itemizedoverlay, currentPositionOvrItem);
        }
        return state;
    }

When onCreate() is called by the system again after the new activity has been created we have to attach back our AsyncTask. You can follow part of the code below.

public void onCreate(Bundle savedInstanceState) {
                                                 .
                                                 .
                                                 .
//The data returned by this method is accessible in onCreate() and onStart() methods.
        if(getLastNonConfigurationInstance() != null){
            ((State) getLastNonConfigurationInstance()).getRequestHandler().attach(this);
            requestHandler = ((State) getLastNonConfigurationInstance()).getRequestHandler();
            //Forget about the lines below for this article
            ((State) getLastNonConfigurationInstance()).getItemizedOverlay().attach(this);
            itemizedoverlay = ((State) getLastNonConfigurationInstance())
                                          .getItemizedOverlay();
           currentPositionOvrItem = ((State)getLastNonConfigurationInstance())
                                          .getCurrentPositionOvrItem();
            redrawOverlayItems();
        }
                                                .
                                                .
                                                .
}

By taking this approach you can avoid memory leaks and also preserve the state of your application while screen rotation happens.