Usman Rana
Usman Rana

Reputation: 2142

Sleepable background service in android

Can I make a background service in android that can go to sleep after doing its job after some specific time? Please guide if you have any idea about this.

Upvotes: 2

Views: 297

Answers (1)

Sanket Prabhu
Sanket Prabhu

Reputation: 2232

Nice question as beginner, But for this you need to know about Intent Service.

1. What is IntentService?

  • IntentService is a subclass of android.app.Service class. A stated intent service allows to handle long running tasks without effecting the application UI thread. This is not bound to any activity so, it is not getting effected for any change in activity lifecycle. Once IntentService is started, it handles each Intent using a worker thread and stops itself when it runs out of work.
  • With IntentService, there can only be one request processed at any single point of time. If you request for another task, then the new job will wait until the previous one is completed. This means that IntentService process the request.
  • An tasks stated using IntentService cannot be interrupted

2. Create an IntentService:

We will create an IntentService to download the data from server. Once download is completed, the response will be sent back to activity. Lets create a new class DownloadService.java and extend it from android.app.IntentService. Now let us override onHandleIntent() method.

public class DownloadService extends IntentService {

    public static final int STATUS_RUNNING = 0;
    public static final int STATUS_FINISHED = 1;
    public static final int STATUS_ERROR = 2;

    private static final String TAG = "DownloadService";

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

    @Override
    protected void onHandleIntent(Intent intent) {

        Log.d(TAG, "Service Started!");

        final ResultReceiver receiver = intent.getParcelableExtra("receiver");
        String url = intent.getStringExtra("url");

        Bundle bundle = new Bundle();

        if (!TextUtils.isEmpty(url)) {
            /* Update UI: Download Service is Running */
            receiver.send(STATUS_RUNNING, Bundle.EMPTY);

            try {
                String[] results = downloadData(url);

                /* Sending result back to activity */
                if (null != results && results.length > 0) {
                    bundle.putStringArray("result", results);
                    receiver.send(STATUS_FINISHED, bundle);
                }
            } catch (Exception e) {

                /* Sending error message back to activity */
                bundle.putString(Intent.EXTRA_TEXT, e.toString());
                receiver.send(STATUS_ERROR, bundle);
            }
        }
        Log.d(TAG, "Service Stopping!");
        this.stopSelf();
    }

    private String[] downloadData(String requestUrl) throws IOException, DownloadException {
        InputStream inputStream = null;
        HttpURLConnection urlConnection = null;

        /* forming th java.net.URL object */
        URL url = new URL(requestUrl);
        urlConnection = (HttpURLConnection) url.openConnection();

        /* optional request header */
        urlConnection.setRequestProperty("Content-Type", "application/json");

        /* optional request header */
        urlConnection.setRequestProperty("Accept", "application/json");

        /* for Get request */
        urlConnection.setRequestMethod("GET");
        int statusCode = urlConnection.getResponseCode();

        /* 200 represents HTTP OK */
        if (statusCode == 200) {
            inputStream = new BufferedInputStream(urlConnection.getInputStream());
            String response = convertInputStreamToString(inputStream);
            String[] results = parseResult(response);
            return results;
        } else {
            throw new DownloadException("Failed to fetch data!!");
        }
    }

    private String convertInputStreamToString(InputStream inputStream) throws IOException {

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line = "";
        String result = "";

        while ((line = bufferedReader.readLine()) != null) {
            result += line;
        }

            /* Close Stream */
        if (null != inputStream) {
            inputStream.close();
        }

        return result;
    }

    private String[] parseResult(String result) {

        String[] blogTitles = null;
        try {
            JSONObject response = new JSONObject(result);
            JSONArray posts = response.optJSONArray("posts");
            blogTitles = new String[posts.length()];

            for (int i = 0; i < posts.length(); i++) {
                JSONObject post = posts.optJSONObject(i);
                String title = post.optString("title");
                blogTitles[i] = title;
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return blogTitles;
    }

    public class DownloadException extends Exception {

        public DownloadException(String message) {
            super(message);
        }

        public DownloadException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}

3.How it works

  1. DownloadService class extending IntentService and overriding onHandleIntent() method. In onHandleIntent() method we will perform our network request to download data from server

  2. Before it downloads the data from server, the request is being fetched from bundle. Our Activity will send this data as extras while starting the

  3. Once Download is successful we will send the response back to activity via ResultReceiver

  4. For any exceptions or error, we will pass the error response back to activity via ResultReceiver.

  5. We have declared custom exception class DownloadException for handling all our custom error messages. You may do this

4. Declaring Service in the Manifest

Like Service, an IntentService also needs an entry in your application manifest. Provide the element entry and declare all your IntentServices you using. Additionally as we are performing operation to download data from internet, we will request for android.permission.INTERNET permission.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.javatechig.intentserviceexample">

    <!-- Internet permission, as we are accessing data from server -->
    <uses-permission android:name="android.permission.INTERNET" />

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

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


        <!-- Declaring Service in Manifest -->
        <service
            android:name=".DownloadService"
            android:exported="false" />

    </application>

</manifest>

6. Sending Work Requests to the IntentService

To start the DownloadService to download data, you must create an explicit Intent and add all the request parameters to it. A service can be started by calling startService() method. You can start an IntentService either form an Activity or a Fragment.

What is the additional DownloadResultReceiver here, huh?. Remember that we have to pass the result of download request from service to activity. This will be done through ResultReceiver.

/* Starting Download Service */
mReceiver = new DownloadResultReceiver(new Handler());
mReceiver.setReceiver(this);
Intent intent = new Intent(Intent.ACTION_SYNC, null, this, DownloadService.class);

/* Send optional extras to Download IntentService */
intent.putExtra("url", url);
intent.putExtra("receiver", mReceiver);
intent.putExtra("requestId", 101);

startService(intent);

Just follow same and change as per your Requirements. And Remember***** Once IntentService is started, it handles each Intent using a worker thread and stops itself when it runs out of work.

Upvotes: 1

Related Questions