IntentService: Working and Advantages of using them

IntentService handles asynchronous requests sent as Intents on demand basis. Request is made via startService(Intent) call. Service is started if needed and it will handled all the requests in turn using a background thread. It will stop by itself as soon as it is done performing the task.

[su_button url=”https://github.com/androidsrc/SampleIntentService” target=”blank” style=”stroked” background=”#51d461″ color=”#ffffff” size=”6″ center=”yes” radius=”0″ icon=”icon: arrow-circle-o-down”]Download Complete Source Code[/su_button]

For using IntentService, create a  class which extends IntentService and implement onHandleIntent(Intent).  It will receive requests and handle them in background thread.

IntentService works on “work queue processor” mechanism and help to take load off from your application main thread.  A single background thread is used to handle all the requests and requests are processed one by one. It might take time to process one request and other one has to wait for that time.

IntentService should be used if we don’t want our service to handle multiple requests simultaneously. For using IntentService, all we need to do is implement onHandleIntent(Intent) method to perform the requested work and provide a constructor for service which must call super("WorkerThreadName").

Sample IntentService Application

We will create an application using IntentService which will download image from internet in background thread of IntentService. We will have main activity with one EditText to specify  url of image and one button to start IntentService from onClick() event.

Lets start with res/layout/activity_main.xmlModify your layout file as below.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context="com.androidsrc.sampleintentservice.MainActivity" >

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_marginBottom="20dp"
 android:layout_marginTop="20dp"
 android:orientation="vertical" >

 <EditText
 android:id="@+id/urlText"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:hint="please enter img url or default will be used"
 android:inputType="textUri" />

 <ProgressBar
 android:id="@+id/downloadPD"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:indeterminateOnly="true"
 android:visibility="gone" />

 <Button
 android:id="@+id/button"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:onClick="onClick"
 android:text="start download with IntentService" />
 </LinearLayout>

 <ImageView
 android:id="@+id/imgView"
 android:layout_width="match_parent"
 android:layout_height="0dp"
 android:layout_weight="1"
 android:scaleType="fitCenter" />

</LinearLayout>

 We need to declare our service in Manifest. And since we will be downloading image from internet we need to take care of permissions as well. Add permission android.permission.INTERNET for internet, android.permission.READ_EXTERNAL_STORAGE and android.permission.WRITE_EXTERNAL_STORAGE for reading and writing to storage.

Update your AndroidManifest.xml as below

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.androidsrc.sampleintentservice"
 android:versionCode="1"
 android:versionName="1.0" >

 <uses-sdk
 android:minSdkVersion="14"
 android:targetSdkVersion="21" />

 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

 <application
 android:allowBackup="true"
 android:icon="@drawable/ic_launcher"
 android:label="@string/app_name"
 android:theme="@style/AppTheme" >
 <activity
 android:name=".MainActivity"
 android:label="@string/app_name" >
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />

 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
 </activity>

 <service
 android:name="com.androidsrc.sampleintentservice.SampleIntentService"
 android:exported="false" >
 </service>
 </application>

</manifest>

Let’s move over to MainActivity.java, We need to implement View.OnClickListener and override onClick(View) method to start IntentSevice from there.  After completion of task in IntentService, If required we need to communicate between Activity and IntentService. We can use simple BroadcastReceiver in our Activity class. We can register it while creating activity with specific IntentFilter, Intent braodcasted from IntentSevice after completion of task can be received in BroadcastReceiver.

In this article, we will use ResultReceiver for communication between Activity and IntentService. With IntentService start intent, we will add extras to intent for url and ResultReceiver. If ResultReceiver object passed to IntentService has Handler from Activity context, it can be used to sending result to Activity using send(int resultCode, Bundle resultData).

Modify your MainActivity.java as below

package com.androidsrc.sampleintentservice;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {

    EditText urlText;
    ProgressBar pd;
    ImageView imgView;
    SampleResultReceiver resultReceiever;
    String defaultUrl = "http://developer.android.com/assets/images/dac_logo.png";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        resultReceiever = new SampleResultReceiver(new Handler());
        urlText = (EditText) findViewById(R.id.urlText);
        pd = (ProgressBar) findViewById(R.id.downloadPD);
        imgView = (ImageView) findViewById(R.id.imgView);
    }

    private class SampleResultReceiver extends ResultReceiver {

        public SampleResultReceiver(Handler handler) {
            super(handler);
        }

        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            switch (resultCode) {
                case SampleIntentService.DOWNLOAD_ERROR:
                    Toast.makeText(getApplicationContext(), "error in download",
                            Toast.LENGTH_SHORT).show();
                    pd.setVisibility(View.INVISIBLE);
                    break;

                case SampleIntentService.DOWNLOAD_SUCCESS:
                    String filePath = resultData.getString("filePath");
                    Bitmap bmp = BitmapFactory.decodeFile(filePath);
                    if ( imgView != null & amp;&amp;
                    bmp != null){
                    imgView.setImageBitmap(bmp);
                    Toast.makeText(getApplicationContext(),
                            "image download via IntentService is done",
                            Toast.LENGTH_SHORT).show();
                } else{
                    Toast.makeText(getApplicationContext(),
                            "error in decoding downloaded file",
                            Toast.LENGTH_SHORT).show();
                }
                pd.setIndeterminate(false);
                pd.setVisibility(View.INVISIBLE);

                break;
            }
            super.onReceiveResult(resultCode, resultData);
        }

    }

    @Override
    public void onClick(View v) {
        Intent startIntent = new Intent(MainActivity.this,
                SampleIntentService.class);
        startIntent.putExtra("receiver", resultReceiever);
        startIntent.putExtra("url",
                TextUtils.isEmpty(urlText.getText()) ? defaultUrl : urlText
                        .getText().toString());
        startService(startIntent);

        pd.setVisibility(View.VISIBLE);
        pd.setIndeterminate(true);
    }
}

Create a class named SampleIntentService.java which will extend IntentService. Add constructor in order to specify name for backround thread and implement onHandleIntent(Intent). In onHandleIntent(Intent), we will retrieve ResultReceiver and url string from intent extras. Open HttpURLConnection for retreived url and write InputStream from connection to FileOutputStream directing to File on device. If task is completed or failed, we notify it via ResultReceiver object.

Your final code should look like as below.

package com.androidsrc.sampleintentservice;

import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class SampleIntentService extends IntentService {

    public static final int DOWNLOAD_ERROR = 10;
    public static final int DOWNLOAD_SUCCESS = 11;

    public SampleIntentService() {
        super(SampleIntentService.class.getName());
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String url = intent.getStringExtra("url");
        final ResultReceiver receiver = intent.getParcelableExtra("receiver");
        Bundle bundle = new Bundle();

        File downloadFile = new File("/sdcard/IntentService_Example.png");
        if (downloadFile.exists())
            downloadFile.delete();
        try {
            downloadFile.createNewFile();
            URL downloadURL = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) downloadURL
                    .openConnection();
            int responseCode = conn.getResponseCode();
            if (responseCode != 200)
                throw new Exception("Error in connection");
            InputStream is = conn.getInputStream();
            FileOutputStream os = new FileOutputStream(downloadFile);
            byte buffer[] = new byte[1024];
            int byteCount;
            while ((byteCount = is.read(buffer)) != -1) {
                os.write(buffer, 0, byteCount);
            }
            os.close();
            is.close();

            String filePath = downloadFile.getPath();
            bundle.putString("filePath", filePath);
            receiver.send(DOWNLOAD_SUCCESS, bundle);

        } catch (Exception e) {
            receiver.send(DOWNLOAD_ERROR, Bundle.EMPTY);
            e.printStackTrace();
        }
    }
}

Screenshots
[su_carousel source=”media: 68,69,66,67″ link=”none” width=”700″ height=”400″ title=”no” mousewheel=”no”]

You may also like...

1 Response

  1. February 18, 2015

    […] We can use IntentService in conjunction with ResultReceiver also for acheiving same result. If interested, you can check our detailed tutorial. Android IntentService: Working and Advantages […]

Leave a Reply

Your email address will not be published. Required fields are marked *