Android Services - Tutorial (2024)

Using styles and themes in Android.Developing own services and using system services in Android.This tutorial describes how to create and consume Android services.

1. Android Services

1.1. What are services?

Aserviceis a component which runs in the background without directinteractionwiththe user. As the service has no userinterface, it isnot bound to the lifecycle of an activity.

Services are used for repetitive and potentially long runningoperations, i.e., Internet downloads, checking fornew data, dataprocessing, updating content providers and the like.

Servicesrun with a higher priority than inactive or invisibleactivitiesand therefore it is less likely that theAndroid systemterminatesthem. Services can also be configured to be restarted ifthey get terminated by the Androidsystem once sufficient systemresources are available again.

It is possible to assign services the same priority asforeground activities. In this case it is required to havea visiblenotification active for the related service. It is frequently usedfor services which play videos or music.

1.2. Services and background processing

By default, aserviceruns in the same process as the main threadof the application.

Therefore, you need to use asynchronous processing in theservicetoperformresource intensive tasksinthebackground. Acommonly used patternfor a service implementation is to create and run a newThreadin the service to perform the processing in the background and thento terminate the service once it has finished theprocessing.

Serviceswhich run in the process of the application are sometimescalledlocalservices.

1.3. Platform service and custom services

The Android platform provides and runspredefined system services andevery Android application can usethem, given theright permissions.These system services areusuallyexposed viaa specific Managerclass. Access to themcan begained viathegetSystemService()method. TheContextclass defines several constants for accessing these services.

An Android application can, in addition to consuming theexistingAndroid platform services, define and use newservices.Defining your customservicesallows you to design responsiveapplications. You can fetch theapplication datavia itand once theapplication is started by the user, it can present freshdata to theuser.

1.4. Starting and defining custom services

Custom services are started from other Android components, i.e.,activities, broadcast receivers and otherservices.

1.5. Foreground services

A foreground service is a service that should have the same priority as an active activity and therefore shouldnot be killed by the Android system, even if the system is low onmemory. A foreground service must provide anotification for the statusbar, which is placed under the "Ongoing" heading,which means that the notification cannotbe dismissed unless theservice is either stopped or removed from theforeground.

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), System.currentTimeMillis());Intent notificationIntent = new Intent(this, ExampleActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);notification.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), pendingIntent);startForeground(ONGOING_NOTIFICATION_ID, notification);

2. Defining custom services

2.1. Implementation and declaration

Aserviceneeds to be declared in theAndroidManifest.xmlfileand the implementing class must extend theServiceclassor oneofits subclasses.

The following code shows an example foraservicedeclaration andits implementation.

<service android:name="MyService" android:icon="@drawable/icon" android:label="@string/service_name" ></service>
public class MyService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { //TODO do something useful return Service.START_NOT_STICKY; } @Override public IBinder onBind(Intent intent) { //TODO for communication return IBinder implementation return null; }}

2.2. Start a service

An Android component (service, receiver, activity)can trigger theexecution of a service viathestartService(intent)method.

// use this to start and trigger a serviceIntent i= new Intent(context, MyService.class);// potentially add data to the intenti.putExtra("KEY1", "Value to be used by the service");context.startService(i);

Alternatively,you can also start aservicevia thebindService()method call. This allows you to communicate directly with theservice.We discuss that later.

2.3. Service start process and execution

If thestartService(intent)method is called and theservice is not yet running, the serviceobject iscreated andtheonCreate()method of the service is called.

Once theserviceis started, theonStartCommand(intent)method in theserviceis called.It passes in theIntentobjectfrom thestartService(intent)call.

IfstartService(intent)is called while the serviceis running, itsonStartCommand()is also called. Therefore yourserviceneeds to be prepared thatonStartCommand()can be called several times.

What if you call this method twice in your code? Do you have to worry about synchronizing the onStartCommand() method call?No, this method is called by the Android system in the main user interface thread, therefore it cannot be called simultaneously from two different threads.

A service is only started once, no matter how often you call thestartService()method.

2.4. Service restart behavior

In itsonStartCommand()method call, the service returns anintwhich defines its restart behavior in case the service gets terminatedby the Android platform. You can use the constants, the most commonoptions are described by the following table.

Table 1. Restart options
OptionDescription

Service.START_STICKY

Service is restarted if it gets terminated.Intent data passed to the onStartCommand method is null.Used for services which manages their own state and do not depend on the Intent data.

Service.START_NOT_STICKY

Service is not restarted.Used for services which are periodically triggered anyway.The service is only restarted if the runtime has pending startService() calls since the service termination.

Service.START_REDELIVER_INTENT

Similar to Service.START_STICKY but the original Intent is re-delivered to the onStartCommand method.

You can check if the service was restarted via theIntent.getFlags()method.START_FLAG_REDELIVERY(in case the service was started withService.START_REDELIVER_INTENT)orSTART_FLAG_RETRY(in case the service was started with Service.START_STICKY)ispassed.

2.5. Stopping a service

Youstopaservicevia thestopService()method. No matter how frequently you called thestartService(intent)method, onecall to thestopService()methodstops the service.

Aservicecan terminate itself by calling thestopSelf()method. This is typically done if the service finishes its work.

3. IntentServices for one time tasks

You can also extend theIntentServiceclass for your service implementation.

TheIntentServiceis used to perform a certain task in the background. Oncedone, theinstance ofIntentServiceterminates itself automatically. An example for its usage would bedownloading certain resources from the internet.

TheIntentServiceclass offers theonHandleIntent()method which will be asynchronously called by the Android system.

4. Communication with services

4.1. Options for communication

There are several possibilities for a communication between an activity and a service.The following description discusses the possible approaches and provides recommendation which to use.

4.2. Using Intent data

In a simple scenario no direct communication is required.The service receives the intent data from the starting Android component and performs its work.No notification is necessary.For example, in case the service updates a content provider, the activity is notified by the content provider and no extra step in the service is necessary.This approach works for local and services running in their own process.

4.3. Using receiver

You can use broadcasts and registered receivers for the communication.For example, your activity can register a broadcast receiver for an event and the service sends outs corresponding events.This is a very typical scenario, in which the service need to signal to the activity that his processing has finished.

This communication flow is depicted in the following graphic.

Android Services - Tutorial (1)

This approach works for local and services running in their own process.

Android provides the LocalBroadcastManagerclass in the support library v4. This is a helper class to registerforand send broadcasts of Intents to local objects within yourprocess. This approach improves security as the broadcast eventsare only visible within your process and is faster than usingstandard events.

4.4. Activity binding to local service

If the service is started in the same process as the activity, the activity can directly bind to the service.This is a relatively simple and efficient way to communicate and recommended for activities which need to have a fast communication layer with the service.

This approach works for local services.

4.5. Handler and ResultReceiver or Messenger

If the service should be communicating back to the activity, it can receive an object of type Messenger via the Intent data it receives from the activity.If the Messenger is bound to a Handler in the activity, the service can send objects of type Message to the activity.

A Messenger is parcelable, which means it can be passed to another process and you can use this object to send Messages to the Handler in the activity.

Messenger also provides the method getBinder() which allows passing a Messenger to the activity.The activity can therefore send Messages to the service.

This approach works for local services running in their own process.

4.6. AIDL for services in a different process

To bind to a service which runs in a different process, you need to use Inter Process Communication (IPC) to community your the data.To do so, you need to create a AIDL file which looks similar to a Java interface, but ends with the .aidl file extension and is only allowed to extend other AIDL files.

This approach is required if you need to bind to a service running in another process, i.e., if your service is consumed by other Android applications.

You can find more information about this approach in the Android developer documentation about AIDL.

5. Scheduling service

See https://www.vogella.com/tutorials/AndroidTaskScheduling/article.html - Android task schedulingto learn how to schedule service periodically.

6. Exercise: Using services and service communication

The following example demonstrates how to use a service to download a file from the Internet based on a button click from an activity.Once done, the service notifies the activity via a broadcast receiver that the download is complete.

In this exercise you use the IntentService class, as this class provides automatic background processing.

Create a new project called com.vogella.android.service.receiver with the activity called MainActivity.

Create the following class for the service.

package com.vogella.android.service.receiver;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.net.URL;import android.app.Activity;import android.app.IntentService;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.os.Environment;import android.os.Message;import android.os.Messenger;import android.util.Log;public class DownloadService extends IntentService { private int result = Activity.RESULT_CANCELED; public static final String URL = "urlpath"; public static final String FILENAME = "filename"; public static final String FILEPATH = "filepath"; public static final String RESULT = "result"; public static final String NOTIFICATION = "com.vogella.android.service.receiver"; public DownloadService() { super("DownloadService"); } // will be called asynchronously by Android @Override protected void onHandleIntent(Intent intent) { String urlPath = intent.getStringExtra(URL); String fileName = intent.getStringExtra(FILENAME); File output = new File(Environment.getExternalStorageDirectory(), fileName); if (output.exists()) { output.delete(); } InputStream stream = null; FileOutputStream fos = null; try { URL url = new URL(urlPath); stream = url.openConnection().getInputStream(); InputStreamReader reader = new InputStreamReader(stream); fos = new FileOutputStream(output.getPath()); int next = -1; while ((next = reader.read()) != -1) { fos.write(next); } // successfully finished result = Activity.RESULT_OK; } catch (Exception e) { e.printStackTrace(); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { e.printStackTrace(); } } if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } publishResults(output.getAbsolutePath(), result); } private void publishResults(String outputPath, int result) { Intent intent = new Intent(NOTIFICATION); intent.putExtra(FILEPATH, outputPath); intent.putExtra(RESULT, result); sendBroadcast(intent); }}

Add this class to the AndroidManifest.xml file.Also add the permission to write to external storage and to access the Internet.The resulting AndroidManifest.xml file should look similar to the following listing.

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.vogella.android.service.receiver" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="17" android:targetSdkVersion="18" /> <uses-permission android:name="android.permission.INTERNET" /> <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="com.vogella.android.service.receiver.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.vogella.android.service.receiver.DownloadService" > </service> </application></manifest>

Change the layout file of your activity to the following.

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Download" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Status: " /> <TextView android:id="@+id/status" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Not started" /> </LinearLayout></LinearLayout>

Change MainActivity to the following.

package com.vogella.android.service.receiver;import android.app.Activity;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.view.View;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity { private TextView textView; private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); if (bundle != null) { String string = bundle.getString(DownloadService.FILEPATH); int resultCode = bundle.getInt(DownloadService.RESULT); if (resultCode == RESULT_OK) { Toast.makeText(MainActivity.this, "Download complete. Download URI: " + string, Toast.LENGTH_LONG).show(); textView.setText("Download done"); } else { Toast.makeText(MainActivity.this, "Download failed", Toast.LENGTH_LONG).show(); textView.setText("Download failed"); } } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.status); } @Override protected void onResume() { super.onResume(); registerReceiver(receiver, new IntentFilter( DownloadService.NOTIFICATION)); } @Override protected void onPause() { super.onPause(); unregisterReceiver(receiver); } public void onClick(View view) { Intent intent = new Intent(this, DownloadService.class); // add infos for the service which file to download and where to store intent.putExtra(DownloadService.FILENAME, "index.html"); intent.putExtra(DownloadService.URL, "https://www.vogella.com/index.html"); startService(intent); textView.setText("Service started"); }}

If you run your example and press the button, the download should be performed by the service.Once done, the user interface is updated and a Toast with the file name is shown.

Change the setting so that the service runs in its own process.Ensure that the application still works, as broadcast receivers are received across process boundaries.

7. Exercise: Define and consume local service

This exercise demonstrates how to bind to a local service from an activity.

The activity binds itself to the service to access its data.

Create a new project called com.vogella.android.localservice with the activity called MainActivity using the Empty Activity template.

Create the following LocalWordService class.

package com.vogella.android.localservice;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.Random;public class LocalWordService extends Service { private final IBinder mBinder = new MyBinder(); private List<String> resultList = new ArrayList<String>(); private int counter = 1; @Override public int onStartCommand(Intent intent, int flags, int startId) { addResultValues(); return Service.START_NOT_STICKY; } @Override public IBinder onBind(Intent intent) { addResultValues(); return mBinder; } public class MyBinder extends Binder { LocalWordService getService() { return LocalWordService.this; } } public List<String> getWordList() { return resultList; } private void addResultValues() { Random random = new Random(); List<String> input = Arrays.asList("Linux", "Android","iPhone","Windows7" ); resultList.add(input.get(random.nextInt(3)) + " " + counter++); if (counter == Integer.MAX_VALUE) { counter = 0; } }}

Register your service in the AndroidManifest.xml file.

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.vogella.android.localservice"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <service android:name=".LocalWordService" android:label="Word service" > </service> </application></manifest>

Change the layout file of the activity similar to the following example.

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <Button android:id="@+id/updateList" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onClick" android:text="Update the list" > </Button> <Button android:id="@+id/triggerServiceUpdate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onClick" android:text="Trigger service" > </Button> </LinearLayout> <ListView android:id="@id/android:list" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView></LinearLayout>

Change your activity class to the following code.

package com.vogella.android.localservice;import android.app.ListActivity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.view.View;import android.widget.ArrayAdapter;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class MainActivity extends ListActivity implements ServiceConnection { private LocalWordService s; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); wordList = new ArrayList<String>(); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, wordList); setListAdapter(adapter); } @Override protected void onResume() { super.onResume(); Intent intent= new Intent(this, LocalWordService.class); bindService(intent, this, Context.BIND_AUTO_CREATE); } @Override protected void onPause() { super.onPause(); unbindService(this); } private ArrayAdapter<String> adapter; private List<String> wordList; public void onClick(View view) { switch (view.getId()) { case R.id.updateList: if (s != null) { Toast.makeText(this, "Number of elements" + s.getWordList().size(), Toast.LENGTH_SHORT).show(); wordList.clear(); wordList.addAll(s.getWordList()); adapter.notifyDataSetChanged(); } break; case R.id.triggerServiceUpdate: Intent service = new Intent(getApplicationContext(), LocalWordService.class); getApplicationContext().startService(service); break; } } @Override public void onServiceConnected(ComponentName name, IBinder binder) { LocalWordService.MyBinder b = (LocalWordService.MyBinder) binder; s = b.getService(); Toast.makeText(MainActivity.this, "Connected", Toast.LENGTH_SHORT).show(); } @Override public void onServiceDisconnected(ComponentName name) { s = null; }}

Run your application.Via your buttons you can update your list or tell the service to fetch more data.

8. Links and Literature

8.1. Android Resources

Android Development Tutorial

Android ListView and ListActivity

Android Location API and Google Maps

Android Intents

Android and Networking

Android Background processing with Threads and Asynchronous Task

If you need more assistance we offer Online Training and Onsite training as well as consulting

See License for license information.

Android Services - Tutorial (2)

Android Services - Tutorial (2024)
Top Articles
Latest Posts
Article information

Author: Lidia Grady

Last Updated:

Views: 5851

Rating: 4.4 / 5 (45 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Lidia Grady

Birthday: 1992-01-22

Address: Suite 493 356 Dale Fall, New Wanda, RI 52485

Phone: +29914464387516

Job: Customer Engineer

Hobby: Cryptography, Writing, Dowsing, Stand-up comedy, Calligraphy, Web surfing, Ghost hunting

Introduction: My name is Lidia Grady, I am a thankful, fine, glamorous, lucky, lively, pleasant, shiny person who loves writing and wants to share my knowledge and understanding with you.