Thursday 16 January 2014

IntentService in Android

In this tutorial I will explain briefly what an IntentService is and how it should be used in an Android app.
To begin with, let's start with a FAQ...


What is a Service?
An Android app is made of components. The most important components are the following: Activity, Service, BroadcastReceiver and ContentProvider.
An IntentService is a special kind of Service and therefore a component of an Android app.

What are Services used for?
Services in Android are generally used for operations that are not directly involved with the user interface (UI). For example: network operations, writing and reading data to/from the local storage (a database, file, etc.), playing music, and other tasks like these.
It is generally better to use one Service for each different task: one Service for network operations, one different Service for managing the database and so on.
Some ot these tasks can also be managed within a normal Activity, using a dedicated thread (AsyncTask or Handler, as I explained in a different tutorial), especially if the data involved comes from the user interface (for example: writing to a local database the data entered by the user).
But there are other tasks (like network operations or playing music) that are bettere managed by Services.
Generally speaking Services allow you to efficiently separate the logic of background tasks from the code that handles the user interface.

Are Services running in a different thread?
No, the code in a Service runs in the main thread (the thread of the GUI). So it is very important to create a different thread within the Service (using an AsyncTask or Handler) to manage long running or slow operations, otherwise they could slow down or block the user interface.

So, what is an IntentService in the end?
An IntentService is a special utility class which represents a Service whose operations run in a different thread than the thread of the GUI.
This is managed automatically by the IntentService class, so you don't have to implement an AsynckTask or a Handler.


Let's see an example.
The following IntentService is used to upload a text or a photo to a remote server in a different thread.

public class MyIntentService extends IntentService {

    //constants
    private static final String CLASSNAME = "MyIntentService";

    //the following 2 actions have to be added in the intent filter for the
    //IntentService in the manifest file
    public static final String ACTION_UPLOAD_TEXT = "com.tutorial.UPLOADTEXT";
    public static final String ACTION_UPLOAD_PHOTO = "com.tutorial.UPLOADPHOTO";
    
    //extras to put in the Intent that starts this IntentService
    public static final String TEXT = "text";
    public static final String PHOTO= "photo";

    public MyIntentService() {
        super(CLASSNAME);

        //if the system shuts down the service, the Intent is not redelivered
        //and therefore the Service won't start again
        setIntentRedelivery(false);
    }

    //this method runs in a different thread (not the main thread)
    @Override
    protected void onHandleIntent(Intent intent) {
        String action = intent.getAction();

        if(action.equals(ACTION_UPLOAD_TEXT)) {
            String text = intent.getStringExtra(TEXT);
            uploadText(text);
        }
        else if(action.equals(ACTION_UPLOAD_PHOTO)) {
            Bitmap photo = itent.getParcelableExtra(PHOTO);
            uploadPhoto(photo);
        }
    }

    private void uploadText(String text) {
        //in this method you upload the text to the server: omitted for brevity
    }

    private void uploadPhoto(Bitmap photo) {
        //in this method you upload the photo to the server: omitted for brevity
    }
}

If you want to use this IntentService from your Activity to upload a text or a photo to the remote server in a dedicated thread, you just have to use the command Context.startService() with the Itent carrying the specific action and extras.

There is only one disadvantage in this approach: if you have multiple calls to the IntentService, these will be put in a queue and processed one at a time (there is no parallel execution). If you need parallel execution, to make sure that each background operation is executed as soon as possibile, you have to use a different approach, but this will be the object of a different tutorial.


2 comments:

  1. Ciao iClaude (i took your name from a forum) :)
    Tell me una bella cosa: what about the Response or Result of an operation, using an IntentService?
    Lets suppose the following scenario:
    1) user want to upload a file (photo, pdf, etc)
    2) the interface launchs IntentService.UploadFile, then continues.
    3) user expects some sort of result message, like "Upload successful", or "Mamma Mia! Everything went wrong!", but the IntentService is still processing the request

    How you can give any feedback to the user?

    ReplyDelete
  2. If you use an IntentService the easiest way to communicate back to the client that launches it is by using a BroadcastReceiver, something like:
    sendBroadcast(new Intent(UPLOAD_COMPLETED));

    Of course you need to implement a BroadcastReceiver on the client to listen for the response.
    This method works even for different applications/processes.

    ReplyDelete