Android Services
1.1 Service
A Service is a component which runs in the background, without interacting with
the user. Every developer can create newServices in his application. Services support true multitasking for Android, as they can run
in their own process. If you use threads in Activities their are still connected to the life-cycle of Activities and the Android system may decide to terminate them at
any point in point.
The
Android platform provides pre-defined Services, usually exposed
via a specific Manager class. Access to these services can be gained via the
method getSystemService().
2.1. Declaring own Services
You
can declare your own Service to perform long running operations without user
interaction or to supply functionality to other applications.
A Service needs to be declared in the AndroidManifest.xml via a <service
android:name="yourclasss"> </service> and the implementing class must extend the Service class or one of its subclasses.
A Service will not automatically run in its own thread. Without
the process attribute, they run the main thread of their hosting process.
Therefore you should run performance intensive tasks in the background.
2.2. Running a Services in its own
process
You
can also specify that your Service runs in a separate process via the android:process=":process_description"attribute.
This way the service gets its own process and
has its own memory. Any long running operation in the Service, e.g. a garbage collection, will not affect the user
interface of your Activity
The colon prefix before the name tells Android
that the Service is private to
its declaring application. If the colon is not used theService would be a global process and can be used by other
components.
<service
android:name="WordService"
android:process=":my_process"
android:icon="@drawable/icon"
android:label="@string/service_name"
>
</service>
Running
a service in its own process will not block the application in case the service
performs long running operations in its main thread. But as the services runs
in its own process you need to use some interprocess communication (IPC) to
communicate to your service from other parts.
While
the base class for creating a Service is the Service class you can also implement IntentService.
The IntentService is used to perform a certain task in the background.
Once done, the instance of IntentService terminate itself automatically. Examples for its usage
would be to download a certain resources from the Internet.
The IntentService class offers the onHandleIntent() method which will be asynchronously called by the
Android system.
An Activity can start a Service via
the startService() method and
stop the service via the stopService() method. If theActivity want
to interact with the Activity it
can use the bindService() method
of the service. This requires anServiceConnection object which allows to connect to the Service and which return a IBinder object. This IBinder object
can be used by the activity to communicate with the Service.
Once a Service is started the onCreate() method is called. Afterwards the onStartCommand() method is called with the Intent data provided by the
activity.
startService() also allows you to provide a
flag which determines the lifecycle behavior of the services.Service.START_STICKY is used for services which are explicit started or
stopped. Services started withService.START_NOT_STICKY will end automatically after the onStartCommand() method is done. A Service is started within the main thread of the application
therefore all long running tasks should be performed in the background.
3. COMMUNICATING WITH SERVICES
There
are several way for an Activity to communicate with an Service and vice versa.
3.1. Binding to local service
If
the Service is started in the same process as the Activity, the Activity can directly bind to the service a call of thebindService() method. This method gets as a parameter a SernviceConnection. The onServiceConnected() method is called on this object once the Service is available. The Service return on its onBind() method an object of type IBinder which can be used to call to the service.
See Local Service Example for an example.
3.2. Binding to a service in a different
process
To
bind to a Service which runs in a different process you need to use
Inter Process Communication (IPC) as the data needs to be send between
different processes. For this you need to create a AIDL file which looks
similiar to an Java Interface but ends with the .aidl file extension and is
only allowed to extend other AIDL files.
If the Android Development Tools find such a
file in your source folder, it will create the necessary stub classes for IPC
communication for your. Still using this approach is relatively advanced and
will not be covered in this tutorial.
3.3. Handler and 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 in bound to a Handler in the Activity the Service can send objects of typeMessage to the Activity.
A Messenger is parcable, which means it can be passed to another
process and you can use this object to send Messages to theHandler in the Activity.
Messenger provides also the method getBinder() which allows to pass a Messenger to the Activity. The Activity can
therefore send Messages to the Service.
Another example would be the usage of . In this
case Activities can send
messages to the Services and
receive messages as well if they register for them.
A
broadcast receiver is a class which extends BroadcastReceiver and
which is registered as a receiver in an Android Application via the AndroidManifest.xml file(or via code).
Alternatively to the this static registration,
you can also register a BroadcastReceiver dynamically via theContext.registerReceiver() method.
This class will be able to receive intents.
Intents can be generated via the Context.sendBroadcast() method.
The class BroadcastReceiver defines the onReceive() method. Only during this method your BroadcastReceiver object will be valid, afterwards the Android system
can recycle the BroadcastReceiver.
Therefore you cannot perform any asynchronous operation in the onReceive() method.
4.2. Sending Broadcast Intents
The sendBroadcast() method allows to send Broadcast Intents. You cannot trigger system Broadcasts, the Android
system will prevent this.
But you can define intent-filters for your own
actions and trigger them via the sendBroadcast() method.
The following AndroidManifest.xml file show a BroadcastReceiver which is registered to a custom action.
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.receiver.own"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<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>
<receiver android:name="MyReceiver" >
<intent-filter>
<action android:name="de.vogella.android.mybroadcast" />
</intent-filter>
</receiver>
</application>
</manifest>
You
can trigger this event via the sendBroadcast() method.
Intent intent = new
Intent();
intent.setAction("de.vogella.android.mybroadcast");
sendBroadcast(intent);
4.3. Sticky Broadcast Intents
A
normal broadcast Intent is not available anymore after is was send and
processed by the system. If you use thesendBroadcast(Intent) method, the Intent is sticky, meaning the Intent you are sending stays around after the broadcast is
complete.
You can can retrieve that data through the
return value of registerReceiver(BroadcastReceiver, IntentFilter) . This works also for a null BroadcastReceiver.
In all other ways, this behaves the same as sendBroadcast(Intent).
The Android system uses sticky broadcast for
certain system information. For example the battery status is send as sticky Intent and can get received at any time. The following
example demonstrates that.
// Register for the
battery changed event
IntentFilter filter =
new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
/ Intent is sticky so
using null as receiver works fine
// return value
contains the status
Intent batteryStatus =
this.registerReceiver(null, filter);
// Are we charging /
charged?
int status =
batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging =
status == BatteryManager.BATTERY_STATUS_CHARGING
|| status == BatteryManager.BATTERY_STATUS_FULL;
boolean isFull =
status == BatteryManager.BATTERY_STATUS_FULL;
// How are we
charging?
int chargePlug =
batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge =
chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
boolean acCharge =
chargePlug == BatteryManager.BATTERY_PLUGGED_AC;
5. SCHEDULING
OF SERVICES
5.1. Automatically starting Services via
Receivers
To
start Services automatically after the Android system starts you can
register a BroadcastReceiver to
the Androidandroid.intent.action.BOOT_COMPLETED system event. This requires theandroid.permission.RECEIVE_BOOT_COMPLETED permission.
The following AndroidManifest.xml registers a
receiver for the BOOT_COMPLETED event.
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.ownservice.local"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name" >
<activity
android:name=".ServiceConsumerActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="MyScheduleReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name="MyStartServiceReceiver" >
</receiver>
</application>
</manifest>
In
the onReceive() method the corresponding BroadcastReceiver would then start the service.
import
android.content.BroadcastReceiver;
import
android.content.Context;
import
android.content.Intent;
public class
MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context,
Intent intent) {
Intent service = new
Intent(context, WordService.class);
context.startService(service);
}
}
If
you application is installed on the SD card, then it is not available after the android.intent.action.BOOT_COMPLETED event. Register yourself in this case for the android.intent.action.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE event.
Also note that as of Android 3.0 the user needs
to have started the application at least once before your application can
receiveandroid.intent.action.BOOT_COMPLETED events.
5.2. Scheduling of Services via AlarmManager
As
with Activities the Android system may terminate the process of a
service at any time to save resources. For this reason you cannot simple use a TimerTask in the service to ensure that it is executed on a
regular basis.
The following would be incorrect, as Android may
terminate your Service.
public void onCreate()
{
super.onCreate();
pollForUpdates();
}
// WRONG, don't do
this
private void
pollForUpdates() {
timer.scheduleAtFixedRate(new
TimerTask() {
@Override
public void run() {
if (list.size() >=
6) {
list.remove(0);
}
list.add(fixedList[index++]);
if (index >=
fixedList.length) {
index = 0;
}
}
}, 0, UPDATE_INTERVAL);
Log.i(getClass().getSimpleName(), "Timer started.");
}
For
correct scheduling of the Service use the AlarmManager class.
A
PendingIntent is a token that you give to another application (e.g.
Notification Manager, Alarm Manager or other 3rd party applications), which
allows this other application to use the permissions of your application to
execute a predefined piece of code.
To perform a broadcast via a pending intent so
get a PendingIntent via PendingIntent.getBroadcast(). To perform an activity via an pending intent you
receive the activity via PendingIntent.getActivity().
We
will define a broadcast receiver which listens to telephone state changes. If
the phone receives a phone call then our receiver will be notified and log a
message.
Create a new project de.vogella.android.receiver.phone. We do not need an Activity. Create the followingAndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.receiver.phone"
android:versionCode="1"
android:versionName="1.0" >
<application
android:icon="@drawable/icon"
android:label="@string/app_name" >
<receiver android:name="MyPhoneReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" >
</action>
</intent-filter>
</receiver>
</application>
<uses-sdk android:minSdkVersion="9" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
</uses-permission>
</manifest>
Create
the MyPhoneReceiver class.
package
de.vogella.android.receiver.phone;
import
android.content.BroadcastReceiver;
import
android.content.Context;
import
android.content.Intent;
import
android.os.Bundle;
import
android.telephony.TelephonyManager;
import
android.util.Log;
public class
MyPhoneReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context,
Intent intent) {
Bundle extras =
intent.getExtras();
if (extras != null) {
String state =
extras.getString(TelephonyManager.EXTRA_STATE);
Log.w("DEBUG", state);
if
(state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
String
phoneNumber = extras
.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.w("DEBUG", phoneNumber);
}
}
}
}
If
you install your application and receive a call, e.g simulated by the DDMS
perspective in Eclipse, then your receiver will be called and lot a message to
the console.
8. TUTORIAL:
SYSTEM SERVICES AND BROADCASTRECEIVER
In
this chapter we will use the AlertManager and VibratorManager. The
VibratorManager will be called by the broadcast receiver which will be called
by the AlertManager.
Create a new project
"de.vogella.android.alarm" with the activity
"AlarmActivity". Create the following layout.
<?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" >
<EditText
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Number of seconds"
android:inputType="numberDecimal" >
</EditText>
<Button
android:id="@+id/ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="startAlert"
android:text="Start Counter" >
</Button>
</LinearLayout>
Create
the following broadcast receiver class. This class will get the Vibrator
service.
package
de.vogella.android.alarm;
import
android.content.BroadcastReceiver;
import
android.content.Context;
import android.content.Intent;
import
android.os.Vibrator;
import
android.widget.Toast;
public class
MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context,
Intent intent) {
Toast.makeText(context, "Don't panik but your time is up!!!!.",
Toast.LENGTH_LONG).show();
// Vibrate the mobile phone
Vibrator vibrator = (Vibrator)
context.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(2000);
}
}
Maintain
this class as broadcast receiver in "AndroidManifest.xml" and allow
the vibrate authorization.
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.alarm" android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="9" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AlarmActivity" android:label="@string/app_name">
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="MyBroadcastReceiver"></receiver>
</application>
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
</manifest>
Change
the code of your Activity "AlarmActivity" to the following. This
activity will create an Intent for the Broadcast receiver and get the AlarmManager
service.
package
de.vogella.android.alarm;
import
android.app.Activity;
import
android.app.AlarmManager;
import
android.app.PendingIntent;
import
android.content.Intent;
import
android.os.Bundle;
import
android.view.View;
import
android.widget.EditText;
import
android.widget.Toast;
public class
AlarmActivity extends Activity {
/** Called when the
activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void startAlert(View view) {
EditText text = (EditText)
findViewById(R.id.time);
int i =
Integer.parseInt(text.getText().toString());
Intent intent = new
Intent(this, MyBroadcastReceiver.class);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(
this.getApplicationContext(), 234324243, intent, 0);
AlarmManager alarmManager =
(AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (i * 1000),
pendingIntent);
Toast.makeText(this, "Alarm set in " + i + " seconds",
Toast.LENGTH_LONG).show();
}
}
Run
your application on the device. Set your time and start the alarm. After the
defined number of seconds a Toast should be displayed. Keep in mind that the
vibrator alarm does not work on the Android emulator.
9. TUTORIAL: USING INTENTSERVICE TO DOWNLOAD A
FILE
The
following will demonstrate how to use the IntentService class to
download a file from the Internet. Once done theIntentService will use an instance of the Messenger class to inform the Activity which started the service about the location of the
downloaded file.
Create a new project called
"de.vogella.android.intentservice.download" with a Activity called "MainActivity".
Create a service "DownloadService" by
creating the following class and the entry in "AndroidManifest.xml".
Also add the permission to write to external storage and to access the Internet
to the file.
package
de.vogella.android.intentservice.download;
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 DownloadService() {
super("DownloadService");
}
// Will be called asynchronously be Android
@Override
protected void onHandleIntent(Intent
intent) {
Uri data = intent.getData();
String urlPath =
intent.getStringExtra("urlpath");
String fileName =
data.getLastPathSegment();
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);
}
// Sucessful 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();
}
}
}
Bundle extras =
intent.getExtras();
if (extras != null) {
Messenger messenger = (Messenger)
extras.get("MESSENGER");
Message msg =
Message.obtain();
msg.arg1 = result;
msg.obj =
output.getAbsolutePath();
try {
messenger.send(msg);
} catch
(android.os.RemoteException e1) {
Log.w(getClass().getName(), "Exception sending message", e1);
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.intentservice.download"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<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="DownloadService" >
</service>
</application>
</manifest>
Change
the "main.xml" layout to the following.
<?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" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Button" />
</LinearLayout>
Change MainActivity to the following.
package
de.vogella.android.intentservice.download;
import
android.app.Activity;
import
android.content.Intent;
import android.net.Uri;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.Message;
import
android.os.Messenger;
import
android.view.View;
import
android.widget.Toast;
public class
MainActivity extends Activity {
private Handler handler = new Handler()
{
public void
handleMessage(Message message) {
Object path =
message.obj;
if (message.arg1 ==
RESULT_OK && path != null) {
Toast.makeText(MainActivity.this,
"Downloaded" + path.toString(), Toast.LENGTH_LONG)
.show();
} else {
Toast.makeText(MainActivity.this,
"Download
failed.",
Toast.LENGTH_LONG).show();
}
};
};
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClick(View view) {
Intent intent = new
Intent(this, DownloadService.class);
// Create a new Messenger for the
communication back
Messenger messenger = new
Messenger(handler);
intent.putExtra("MESSENGER", messenger);
intent.setData(Uri.parse("http://www.vogella.de/index.html"));
intent.putExtra("urlpath", "http://www.vogella.de/index.html");
startService(intent);
}
}
If
you run your example and press the button, the download should be performed by
the Service and once done the Activity should show a Toast with the file name.
10.DEFINE
AND CONSUME YOUR OWN LOCAL SERVICE
The
following chapter will demonstrate how to create and consume a service from an
activity. The service will be started at boot and periodically fetch data. The
service will used by an activity which bind itself to the service. The activity will
allow to request the latest data from the service.
Create a new project called
"de.vogella.android.ownservice.local" with a Activity called "MainActivity".
Create the LocalWordService class.
package
de.vogella.android.ownservice.local;
import
java.util.ArrayList;
import java.util.List;
import
java.util.Random;
import
android.app.Service;
import
android.content.Intent;
import
android.os.Binder;
import
android.os.IBinder;
public class
LocalWordService extends Service {
private final IBinder mBinder = new
MyBinder();
private ArrayList<String> list =
new ArrayList<String>();
@Override
public int onStartCommand(Intent
intent, int flags, int startId) {
Random random = new Random();
if (random.nextBoolean()) {
list.add("Linux");
}
if (random.nextBoolean()) {
list.add("Android");
}
if (random.nextBoolean()) {
list.add("iPhone");
}
if (random.nextBoolean()) {
list.add("Windows7");
}
if (list.size() >= 20) {
list.remove(0);
}
return
Service.START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class MyBinder extends Binder {
LocalWordService getService() {
return
LocalWordService.this;
}
}
public List<String> getWordList()
{
ArrayList<String> list =
new ArrayList<String>();
return list;
}
}
Create
the following two classes, which will be registered as BroadcastReceivers.
package
de.vogella.android.ownservice.local;
import
java.util.Calendar;
import
android.app.AlarmManager;
import
android.app.PendingIntent;
import
android.content.BroadcastReceiver;
import
android.content.Context;
import
android.content.Intent;
public class
MyScheduleReceiver extends BroadcastReceiver {
// Restart service every 30 seconds
private static final long REPEAT_TIME =
1000 * 30;
@Override
public void onReceive(Context context,
Intent intent) {
AlarmManager service =
(AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context,
MyStartServiceReceiver.class);
PendingIntent pending =
PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
Calendar cal =
Calendar.getInstance();
// Start 30 seconds after boot completed
cal.add(Calendar.SECOND, 30);
//
// Fetch every 30 seconds
// InexactRepeating allows Android to optimize
the energy consumption
service.setInexactRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(), REPEAT_TIME, pending);
//
service.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
// REPEAT_TIME, pending);
}
}
package
de.vogella.android.ownservice.local;
import
android.content.BroadcastReceiver;
import
android.content.Context;
import
android.content.Intent;
public class
MyStartServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context,
Intent intent) {
Intent service = new
Intent(context, LocalWordService.class);
context.startService(service);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.ownservice.local"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name" >
<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=".LocalWordService"
android:icon="@drawable/icon"
android:label="@string/service_name" >
</service>
<receiver android:name="MyScheduleReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name="MyStartServiceReceiver" >
</receiver>
</application>
</manifest>
Change
the "main.xml" layout to the following.
<?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" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showServiceData"
android:text="Button" >
</Button>
<ListView
android:id="@id/android:list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
Change
your Activity to the following.
package
de.vogella.android.ownservice.local;
import
java.util.ArrayList;
import java.util.List;
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;
public class
MainActivity extends ListActivity {
private LocalWordService s;
/** Called when the
activity is first created. */
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
wordList = new
ArrayList<String>();
adapter = new
ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1,
wordList);
setListAdapter(adapter);
doBindService();
}
private ServiceConnection mConnection =
new ServiceConnection() {
public void
onServiceConnected(ComponentName className, IBinder binder) {
s =
((LocalWordService.MyBinder) binder).getService();
Toast.makeText(MainActivity.this, "Connected",
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName
className) {
s = null;
}
};
private ArrayAdapter<String>
adapter;
private List<String> wordList;
void doBindService() {
bindService(new Intent(this,
LocalWordService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
public void showServiceData(View view)
{
if (s != null) {
Toast.makeText(this, "Number of elements" + s.getWordList().size(),
Toast.LENGTH_SHORT).show();
wordList.clear();
wordList.addAll(s.getWordList());
adapter.notifyDataSetChanged();
}
}
}
11. TUTORIAL: INTERPROCESS COMMUNICATION WITH
MESSENGER
The
following chapter will demonstrate how to communicate between an Activity and an Service using the Messenger andHandler class.
Create a new project called
"de.vogella.android.ownservice.messenger" with an Activity called "MainActivity".
Creating the following
"AndroidManifest.xml".
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.ownservice.messenger"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<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="DownloadServiceMessenger" >
</service>
</application>
</manifest>
Create
the following class
package
de.vogella.android.ownservice.messenger;
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.Service;
import
android.content.Intent;
import
android.os.Bundle;
import
android.os.Environment;
import
android.os.Handler;
import
android.os.IBinder;
import android.os.Message;
import
android.os.Messenger;
import
android.os.StrictMode;
import
android.util.Log;
public class
DownloadServiceMessenger extends Service {
public static final String FILENAME = "fileName";
public static final String URLPATH = "urlPath";
public static final String RESULTPATH =
"urlPath";
private int result =
Activity.RESULT_CANCELED;
// Used to receive messages from the Activity
final Messenger inMessenger = new
Messenger(new IncomingHandler());
// Use to send message to the Activity
private Messenger outMessenger;
public DownloadServiceMessenger() {
super();
// Don't do this
// Network Stuff will run in the main thread
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
}
class IncomingHandler extends Handler {
@Override
public void
handleMessage(Message msg) {
Log.e("MESSAGE", "Got message");
Bundle data =
msg.getData();
String urlPath =
data.getString(DownloadServiceMessenger.URLPATH);
String fileName =
data.getString(DownloadServiceMessenger.FILENAME);
String outputPath =
download(urlPath, fileName);
Message backMsg = Message.obtain();
backMsg.arg1 = result;
Bundle bundle = new
Bundle();
bundle.putString(RESULTPATH, outputPath);
backMsg.setData(bundle);
try {
outMessenger.send(backMsg);
} catch
(android.os.RemoteException e1) {
Log.w(getClass().getName(), "Exception sending message", e1);
}
}
}
private String download(String urlPath,
String 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);
}
// Sucessful 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();
}
}
}
return
output.getAbsolutePath();
}
@Override
public IBinder onBind(Intent intent) {
Bundle extras =
intent.getExtras();
// Get messager from the Activity
if (extras != null) {
outMessenger = (Messenger)
extras.get("MESSENGER");
}
// Return our messenger to the Activity to get
commands
return inMessenger.getBinder();
}
}
Change
the "main.xml" layout to the following.
<?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" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Button" />
</LinearLayout>
Change MainActivity to the following.
package
de.vogella.android.ownservice.messenger;
import
android.app.Activity;
import
android.content.ComponentName;
import
android.content.Context;
import
android.content.Intent;
import
android.content.ServiceConnection;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.IBinder;
import
android.os.Message;
import
android.os.Messenger;
import
android.os.RemoteException;
import
android.view.View;
import android.widget.Toast;
public class
MainActivity extends Activity {
Messenger messenger = null;
private Handler handler = new Handler()
{
public void
handleMessage(Message message) {
Bundle data =
message.getData();
if (message.arg1 ==
RESULT_OK && data != null) {
String text =
data
.getString(DownloadServiceMessenger.RESULTPATH);
Toast.makeText(MainActivity.this,
text, Toast.LENGTH_LONG)
.show();
}
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
private ServiceConnection conn = new
ServiceConnection() {
public void
onServiceConnected(ComponentName className, IBinder binder) {
messenger = new
Messenger(binder);
}
public void
onServiceDisconnected(ComponentName className) {
messenger = null;
}
};
protected void onResume() {
super.onResume();
Toast.makeText(this, "OnResume called", Toast.LENGTH_SHORT).show();
Intent intent = null;
intent = new Intent(this,
DownloadServiceMessenger.class);
// Create a new Messenger for the
communication back
// From the Service to the Activity
Messenger messenger = new
Messenger(handler);
intent.putExtra("MESSENGER", messenger);
bindService(intent, conn,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onPause() {
super.onPause();
unbindService(conn);
}
public void onClick(View view) {
Message msg = Message.obtain();
try {
Bundle bundle = new
Bundle();
bundle.putString(DownloadServiceMessenger.FILENAME, "index.html");
bundle.putString(DownloadServiceMessenger.URLPATH,
"http://www.vogella.de/index.html");
msg.setData(bundle);
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
Services
A Service is an application component that
can perform long-running operations in the background and does not provide a
user interface. Another application component can start a service and it will
continue to run in the background even if the user switches to another
application. Additionally, a component can bind to a service to interact with
it and even perform interprocess communication (IPC). For example, a service
might handle network transactions, play music, perform file I/O, or interact
with a content provider, all from the background.
A service can essentially take two forms:
Started
A service is "started" when an
application component (such as an activity) starts it by calling startService(). Once started, a service can
run in the background indefinitely, even if the component that started it is
destroyed. Usually, a started service performs a single operation and does not
return a result to the caller. For example, it might download or upload a file
over the network. When the operation is done, the service should stop itself.
Bound
A service is "bound" when an application component
binds to it by calling bindService(). A bound service offers a
client-server interface that allows components to interact with the service,
send requests, get results, and even do so across processes with interprocess
communication (IPC). A bound service runs only as long as another application
component is bound to it. Multiple components can bind to the service at once,
but when all of them unbind, the service is destroyed.
Although this
documentation generally discusses these two types of services separately, your
service can work both ways—it can be started (to run indefinitely) and also
allow binding. It's simply a matter of whether you implement a couple callback
methods:onStartCommand() to allow components to
start it and onBind() to allow binding.
Regardless of whether your application is started, bound, or both, any
application component can use the service (even from a separate application),
in the same way that any component can use an activity—by starting it with an Intent. However, you can declare the service
as private, in the manifest file, and block access from other applications.
This is discussed more in the section about Declaring the service in the manifest.
Caution: A service runs in the main thread of its hosting
process—the service does not create its own thread and does not run
in a separate process (unless you specify otherwise). This means that, if your
service is going to do any CPU intensive work or blocking operations (such as
MP3 playback or networking), you should create a new thread within the service
to do that work. By using a separate thread, you will reduce the risk of
Application Not Responding (ANR) errors and the application's main thread can
remain dedicated to user interaction with your activities.
Should you use a service or a thread?
A service is simply a
component that can run in the background even when the user is not interacting
with your application. Thus, you should create a service only if that is what
you need.
If you need to perform work outside your main thread, but only while the user
is interacting with your application, then you should probably instead create a
new thread and not a service. For example, if you want to play some music, but
only while your activity is running, you might create a thread in onCreate(), start running it in onStart(), then stop it in onStop(). Also consider usingAsyncTask or HandlerThread, instead of the traditional Thread class. See the Processes and Threading document for more
information about threads.
Remember that if you do use a service, it still runs in your application's main
thread by default, so you should still create a new thread within the service
if it performs intensive or blocking operations.
To create a service, you must create a subclass of Service (or one of its existing
subclasses). In your implementation, you need to override some callback methods
that handle key aspects of the service lifecycle and provide a mechanism for
components to bind to the service, if appropriate. The most important callback
methods you should override are:
The system calls this method when another
component, such as an activity, requests that the service be started, by
callingstartService(). Once this method executes, the
service is started and can run in the background indefinitely. If you implement
this, it is your responsibility to stop the service when its work is done, by
calling stopSelf() or stopService(). (If you only want to provide
binding, you don't need to implement this method.)
The system calls this method when another
component wants to bind with the service (such as to perform RPC), by callingbindService(). In your implementation of this
method, you must provide an interface that clients use to communicate with the
service, by returning an IBinder. You must always implement this
method, but if you don't want to allow binding, then you should return null.
The system calls this method when the service
is first created, to perform one-time setup procedures (before it calls eitheronStartCommand() or onBind()). If the service is already running,
this method is not called.
The system calls this method when the service is no longer used
and is being destroyed. Your service should implement this to clean up any
resources such as threads, registered listeners, receivers, etc. This is the
last call the service receives.
If a component starts
the service by calling startService() (which results in a call
to onStartCommand()), then the service remains
running until it stops itself with stopSelf() or another component stops it
by calling stopService().
If a component calls bindService() to create the service (and onStartCommand() is not called),
then the service runs only as long as the component is bound to it. Once the
service is unbound from all clients, the system destroys it.
The Android system will force-stop a service only when memory is low and it must
recover system resources for the activity that has user focus. If the service
is bound to an activity that has user focus, then it's less likely to be
killed, and if the service is declared to run in the foreground (discussed later),
then it will almost never be killed. Otherwise, if the service was started and
is long-running, then the system will lower its position in the list of
background tasks over time and the service will become highly susceptible to
killing—if your service is started, then you must design it to gracefully
handle restarts by the system. If the system kills your service, it restarts it
as soon as resources become available again (though this also depends on the
value you return from onStartCommand(), as discussed later). For
more information about when the system might destroy a service, see the Processes and Threading document.
In the following sections, you'll see how you can create each type of service
and how to use it from other application components.
Declaring a service in the manifest
Like activities (and
other components), you must declare all services in your application's manifest
file.
To declare your service, add a <service> element as a child of the <application> element. For example:
<manifest ... >
...
<application
... >
<service android:name=".ExampleService" />
...
</application>
</manifest>
There are other
attributes you can include in the <service> element to define
properties such as permissions required to start the service and the process in
which the service should run. The android:name attribute is the only
required attribute—it specifies the class name of the service. Once you publish
your application, you should not change this name, because if you do, you might
break some functionality where explicit intents are used to reference your
service (read the blog post, Things That Cannot Change).
See the <service> element reference for
more information about declaring your service in the manifest.
Just like an activity, a service can define intent filters that allow other
components to invoke the service using implicit intents. By declaring intent
filters, components from any application installed on the user's device can
potentially start your service if your service declares an intent filter that
matches the intent another application passes to startService().
If you plan on using your service only locally (other applications do not use
it), then you don't need to (and should not) supply any intent filters. Without
any intent filters, you must start the service using an intent that explicitly
names the service class. More information aboutstarting a service is discussed below.
Additionally, you can ensure that your service is private to your application
only if you include the android:exported attribute and set it to "false".
This is effective even if your service supplies intent filters.
For more information about creating intent filters for your service, see the Intents and Intent Filters document.
CREATING A STARTED SERVICE
TARGETING ANDROID 1.6
OR LOWER
If you're building an
application for Android 1.6 or lower, you need to implement onStart(), instead of onStartCommand() (in Android 2.0, onStart() was deprecated in favor of onStartCommand()).
For more information about providing compatibility with versions of Android
older than 2.0, see the onStartCommand()documentation.
A started service is one that another component starts by calling startService(), resulting in a call to the
service'sonStartCommand() method.
When a service is started, it has a lifecycle that's independent of the
component that started it and the service can run in the background
indefinitely, even if the component that started it is destroyed. As such, the
service should stop itself when its job is done by calling stopSelf(), or another component can stop it
by calling stopService().
An application component such as an activity can start the service by calling startService() and passing an Intent that specifies the service and
includes any data for the service to use. The service receives this Intent in the onStartCommand() method.
For instance, suppose an activity needs to save some data to an online
database. The activity can start a companion service and deliver it the data to
save by passing an intent to startService(). The service receives the
intent in onStartCommand(), connects to the Internet and
performs the database transaction. When the transaction is done, the service
stops itself and it is destroyed.
Caution: A services runs in the same process as the application in
which it is declared and in the main thread of that application, by default.
So, if your service performs intensive or blocking operations while the user
interacts with an activity from the same application, the service will slow
down activity performance. To avoid impacting application performance, you
should start a new thread inside the service.
Traditionally, there are two classes you can extend to create a started
service:
This is the base class for all services. When
you extend this class, it's important that you create a new thread in which to
do all the service's work, because the service uses your application's main
thread, by default, which could slow the performance of any activity your
application is running.
This is a subclass of Service that uses a worker thread to
handle all start requests, one at a time. This is the best option if you don't
require that your service handle multiple requests simultaneously. All you need
to do is implement onHandleIntent(), which receives the intent
for each start request so you can do the background work.
The following sections
describe how you can implement your service using either one for these classes.
Extending the IntentService class
Because most started
services don't need to handle multiple requests simultaneously (which can
actually be a dangerous multi-threading scenario), it's probably best if you
implement your service using the IntentService class.
The IntentService does the following:
·
Creates a default
worker thread that executes all intents delivered to onStartCommand() separate from your
application's main thread.
·
Creates a work queue
that passes one intent at a time to your onHandleIntent() implementation, so you
never have to worry about multi-threading.
·
Stops the service
after all start requests have been handled, so you never have to call stopSelf().
·
Provides default
implementation of onBind() that returns null.
All this adds up to
the fact that all you need to do is implement onHandleIntent() to do the work provided
by the client. (Though, you also need to provide a small constructor for the
service.)
Here's an example implementation of IntentService:
public class
HelloIntentService extends IntentService {
/**
*
constructor with a name for the worker thread.
*/
public
HelloIntentService() {
super("HelloIntentService");
}
/**
* The
IntentService calls this method from the default worker thread with
* the
intent that started the service. When this method returns, IntentService
* stops
the service, as appropriate.
*/
@Override
protected void
onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime -
System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
}
@Override
public int
onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
return
super.onStartCommand(intent,flags,startId);
}
Besides onHandleIntent(), the only method from which
you don't need to call the super class is onBind() (but you only need to implement
that if your service allows binding).
In the next section, you'll see how the same kind of service is implemented
when extending the base Service class, which is a lot more code,
but which might be appropriate if you need to handle simultaneous start
requests.
Extending the Service class
As you saw in the
previous section, using IntentService makes your implementation
of a started service very simple. If, however, you require your service to
perform multi-threading (instead of processing start requests through a work
queue), then you can extend the Service class to handle each intent.
For comparison, the following example code is an implementation of the Service class that performs the exact
same work as the example above using IntentService. That is, for each start
request, it uses a worker thread to perform the job and processes only one
request at a time.
public class
HelloService extends Service {
private Looper
mServiceLooper;
private
ServiceHandler mServiceHandler;
// Handler that
receives messages from the thread
private final
class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime -
System.currentTimeMillis());
} catch (Exception e) {
}
}
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
@Override
public void
onCreate() {
// Start
up the thread running the service. Note that we create a
//
separate thread because the service normally runs in the process's
// main
thread, which we don't want to block. We also make it
//
background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get
the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int
onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder
onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void
onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
As you can see, it's a
lot more work than using IntentService.
However, because you handle each call to onStartCommand() yourself, you can
perform multiple requests simultaneously. That's not what this example does, but
if that's what you want, then you can create a new thread for each request and
run them right away (instead of waiting for the previous request to finish).
Notice that the onStartCommand() method must return an
integer. The integer is a value that describes how the system should continue
the service in the event that the system kills it (as discussed above, the default
implementation for IntentService handles this for you,
though you are able to modify it). The return value from onStartCommand() must be one of the
following constants:
If the system kills the service after onStartCommand() returns, do not recreate
the service, unless there are pending intents to deliver. This is the safest
option to avoid running your service when not necessary and when your
application can simply restart any unfinished jobs.
If the system kills the service after onStartCommand() returns, recreate the
service and call onStartCommand(), but do notredeliver
the last intent. Instead, the system calls onStartCommand() with a null intent,
unless there were pending intents to start the service, in which case, those
intents are delivered. This is suitable for media players (or similar services)
that are not executing commands, but running indefinitely and waiting for a job.
If the system kills the service after onStartCommand() returns, recreate the
service and call onStartCommand() with the last intent
that was delivered to the service. Any pending intents are delivered in turn.
This is suitable for services that are actively performing a job that should be
immediately resumed, such as downloading a file.
For more details about
these return values, see the linked reference documentation for each constant.
You can start a
service from an activity or other application component by passing an Intent (specifying the service to start)
tostartService(). The Android system calls the
service's onStartCommand() method and passes it the Intent. (You should never call onStartCommand() directly.)
For example, an activity can start the example service in the previous section
(HelloSevice) using an explicit intent withstartService():
Intent intent = new
Intent(this, HelloService.class);
startService(intent);
The startService() method returns immediately
and the Android system calls the service's onStartCommand() method. If the service
is not already running, the system first calls onCreate(), then calls onStartCommand().
If the service does not also provide binding, the intent delivered with startService() is the only mode of
communication between the application component and the service. However, if
you want the service to send a result back, then the client that starts the
service can create a PendingIntent for a broadcast (with getBroadcast()) and deliver it to the service
in the Intent that starts the service. The
service can then use the broadcast to deliver a result.
Multiple requests to start the service result in multiple corresponding calls
to the service's onStartCommand(). However, only one request to
stop the service (with stopSelf() or stopService()) is required to stop it.
A started service must
manage its own lifecycle. That is, the system does not stop or destroy the
service unless it must recover system memory and the service continues to run
after onStartCommand() returns. So, the service
must stop itself by calling stopSelf()or another component can stop it by
calling stopService().
Once requested to stop with stopSelf() or stopService(), the system destroys the service
as soon as possible.
However, if your service handles multiple requests to onStartCommand() concurrently, then you
shouldn't stop the service when you're done processing a start request, because
you might have since received a new start request (stopping at the end of the
first request would terminate the second one). To avoid this problem, you can
use stopSelf(int) to ensure that your request
to stop the service is always based on the most recent start request. That is,
when you call stopSelf(int), you pass the ID of the start
request (the startId delivered to onStartCommand()) to which your stop request
corresponds. Then if the service received a new start request before you were
able to call stopSelf(int), then the ID will not match and
the service will not stop.
Caution: It's important that your application stops its services
when it's done working, to avoid wasting system resources and consuming battery
power. If necessary, other components can stop the service by calling stopService(). Even if you enable binding for
the service, you must always stop the service yourself if it ever received a
call to onStartCommand().
For more information about the lifecycle of a service, see the section below
about Managing the Lifecycle of a Service.
A bound service is one
that allows application components to bind to it by calling bindService() in order to create a
long-standing connection (and generally does not allow components to start it
by calling startService()).
You should create a bound service when you want to interact with the service
from activities and other components in your application or to expose some of
your application's functionality to other applications, through interprocess
communication (IPC).
To create a bound service, you must implement the onBind() callback method to return an IBinder that defines the interface for communication
with the service. Other application components can then call bindService() to retrieve the interface
and begin calling methods on the service. The service lives only to serve the
application component that is bound to it, so when there are no components
bound to the service, the system destroys it (you do not need
to stop a bound service in the way you must when the service is started through onStartCommand()).
To create a bound service, the first thing you must do is define the interface
that specifies how a client can communicate with the service. This interface
between the service and a client must be an implementation of IBinder and is what your service must
return from the onBind() callback method. Once the client
receives the IBinder, it can begin interacting with the
service through that interface.
Multiple clients can bind to the service at once. When a client is done
interacting with the service, it calls unbindService() to unbind. Once there are
no clients bound to the service, the system destroys the service.
There are multiple ways to implement a bound service and the implementation is
more complicated than a started service, so the bound service discussion
appears in a separate document about Bound Services.
SENDING
NOTIFICATIONS TO THE USER
Once running, a
service can notify the user of events using Toast Notifications or Status Bar Notifications.
A toast notification is a message that appears on the surface of the current
window for a moment then disappears, while a status bar notification provides
an icon in the status bar with a message, which the user can select in order to
take an action (such as start an activity).
Usually, a status bar notification is the best technique when some background
work has completed (such as a file completed downloading) and the user can now
act on it. When the user selects the notification from the expanded view, the
notification can start an activity (such as to view the downloaded file).
See the Toast Notifications or Status Bar Notifications developer guides
for more information.
RUNNING
A SERVICE IN THE FOREGROUND
A foreground service
is a service that's considered to be something the user is actively aware of
and thus not a candidate for the system to kill when low on memory. A
foreground service must provide a notification for the status bar, which is
placed under the "Ongoing" heading, which means that the notification
cannot be dismissed unless the service is either stopped or removed from the
foreground.
For example, a music player that plays music from a service should be set to
run in the foreground, because the user is explicitly aware of its operation.
The notification in the status bar might indicate the current song and allow
the user to launch an activity to interact with the music player.
To request that your service run in the foreground, call startForeground(). This method takes two
parameters: an integer that uniquely identifies the notification and the Notification for the status bar. For
example:
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,
notification);
To remove the service
from the foreground, call stopForeground(). This method takes a boolean,
indicating whether to remove the status bar notification as well. This method
does not stop the service. However, if you stop the service
while it's still running in the foreground, then the notification is also
removed.
Note: The methods startForeground() and stopForeground() were introduced in
Android 2.0 (API Level 5). In order to run your service in the foreground on
older versions of the platform, you must use the previous setForeground() method—see
thestartForeground() documentation for
information about how to provide backward compatibility.
For more information about notifications, see Creating Status Bar Notifications.
MANAGING
THE LIFECYCLE OF A SERVICE
The lifecycle of a
service is much simpler than that of an activity. However, it's even more
important that you pay close attention to how your service is created and
destroyed, because a service can run in the background without the user being
aware.
The service lifecycle—from when it's created to when it's destroyed—can follow
two different paths:
·
A started service
The service is created when another component calls startService(). The service then runs
indefinitely and must stop itself by calling stopSelf(). Another component can also stop
the service by calling stopService(). When the service is stopped,
the system destroys it..
·
A bound service
The service is created when another component (a client) calls bindService(). The client then communicates
with the service through an IBinder interface. The client can close
the connection by calling unbindService(). Multiple clients can bind to
the same service and when all of them unbind, the system destroys the service.
(The service does not need to stop itself.)
These two paths are
not entirely separate. That is, you can bind to a service that was already
started with startService(). For example, a background
music service could be started by calling startService() with an Intent that identifies the music to play.
Later, possibly when the user wants to exercise some control over the player or
get information about the current song, an activity can bind to the service by
calling bindService(). In cases like this, stopService() or stopSelf() does not actually stop the
service until all clients unbind.
Implementing the lifecycle callbacks
Like an activity, a
service has lifecycle callback methods that you can implement to monitor
changes in the service's state and perform work at the appropriate times. The
following skeleton service demonstrates each of the lifecycle methods:
Figure 2. The service lifecycle. The diagram on the left shows the
lifecycle when the service is created with startService() and the diagram on the
right shows the lifecycle when the service is created with bindService().
public class
ExampleService extends Service {
int
mStartMode; // indicates how to behave if the service is
killed
IBinder
mBinder; // interface for clients that bind
boolean
mAllowRebind; // indicates whether onRebind should be used
@Override
// The service is being created
}
@Override
return mStartMode;
}
@Override
public
IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public
boolean onUnbind(Intent intent) {
return mAllowRebind;
}
@Override
// after onUnbind() has already been called
}
@Override
// The service is no longer used and is being destroyed
}
}
Note: Unlike the activity lifecycle callback
methods, you are not required to call the superclass
implementation of these callback methods.
By implementing these methods, you can monitor two nested loops of the
service's lifecycle:
·
The active
lifetime of a service begins with a call to either onStartCommand() or onBind(). Each method is handed the Intent that was passed to either startService() or bindService(), respectively.
If the service is started, the active lifetime ends the same time that the
entire lifetime ends (the service is still active even after onStartCommand() returns). If the service
is bound, the active lifetime ends when onUnbind() returns.
Note: Although a started service is stopped by
a call to either stopSelf() or stopService(), there is not a respective
callback for the service (there's no onStop() callback). So, unless
the service is bound to a client, the system destroys it when the service is
stopped—onDestroy() is the only callback
received.
Figure 2 illustrates the typical callback methods for a service. Although the
figure separates services that are created bystartService() from those created by bindService(), keep in mind that any service,
no matter how it's started, can potentially allow clients to bind to it. So, a
service that was initially started with onStartCommand() (by a client calling startService()) can still receive a call to onBind() (when a client calls bindService()).
For more information about creating a service that provides binding, see the Bound Services document, which includes
more information about the onRebind() callback method in the section
about Managing the Lifecycle of a Bound Service.
Bound Services
·
A bound service allows
other components to bind to it, in order to interact with it and perform
interprocess communication
·
A bound service is
destroyed once all clients unbind, unless the service was also started
IN THIS DOCUMENT
KEY CLASSES
SAMPLES
SEE ALSO
A bound service is the
server in a client-server interface. A bound service allows components (such as
activities) to bind to the service, send requests, receive responses, and even
perform interprocess communication (IPC). A bound service typically lives only
while it serves another application component and does not run in the
background indefinitely.
This document shows you how to create a bound service, including how to bind to
the service from other application components. However, you should also refer
to the Services document for additional
information about services in general, such as how to deliver notifications
from a service, set the service to run in the foreground, and more.
THE BASICS
A bound service is an
implementation of the Service class that allows other
applications to bind to it and interact with it. To provide binding for a
service, you must implement the onBind() callback method. This method
returns an IBinder object that defines the
programming interface that clients can use to interact with the service.
Binding to a Started Service
As discussed in the Services document, you can create a
service that is both started and bound. That is, the service can be started by
calling startService(), which allows the service to
run indefinitely, and also allow a client to bind to the service by callingbindService().
If you do allow your service to be started and bound, then when the service has
been started, the system does not destroy the service when all
clients unbind. Instead, you must explicitly stop the service, by calling stopSelf() or stopService().
Although you should usually implement either onBind() or onStartCommand(), it's sometimes necessary to
implement both. For example, a music player might find it useful to allow its
service to run indefinitely and also provide binding. This way, an activity can
start the service to play some music and the music continues to play even if
the user leaves the application. Then, when the user returns to the
application, the activity can bind to the service to regain control of
playback.
Be sure to read the section about Managing the Lifecycle of a Bound Service, for
more information about the service lifecycle when adding binding to a started
service.
A client can bind to the service by calling bindService(). When it does, it must provide
an implementation ofServiceConnection, which monitors the
connection with the service. The bindService() method returns immediately
without a value, but when the Android system creates the connection between the
client and service, it calls onServiceConnected() on theServiceConnection, to deliver the IBinder that the client can use to
communicate with the service.
Multiple clients can connect to the service at once. However, the system calls
your service's onBind() method to retrieve theIBinder only when the first client binds.
The system then delivers the same IBinder to any additional clients that
bind, without callingonBind() again.
When the last client unbinds from the service, the system destroys the service
(unless the service was also started bystartService()).
When you implement your bound service, the most important part is defining the
interface that your onBind() callback method returns. There
are a few different ways you can define your service's IBinder interface and the following
section discusses each technique.
CREATING A BOUND SERVICE
When creating a
service that provides binding, you must provide an IBinder that provides the programming
interface that clients can use to interact with the service. There are three
ways you can define the interface:
If your service is private to your own application and runs in
the same process as the client (which is common), you should create your
interface by extending the Binder class and returning an instance of
it from onBind(). The client receives the Binderand can use it to directly access public
methods available in either the Binder implementation or even the Service.
This is the preferred technique when your service is merely a
background worker for your own application. The only reason you would not
create your interface this way is because your service is used by other
applications or across separate processes.
If you need your interface to work across different processes,
you can create an interface for the service with a Messenger. In this manner, the service defines
a Handler that responds to different types
of Message objects. This Handler is the basis for aMessenger that can then share an IBinder with the client, allowing the
client to send commands to the service using Messageobjects. Additionally, the client can
define a Messenger of its own so the service can
send messages back.
This is the simplest way to perform interprocess communication
(IPC), because the Messenger queues all requests into a
single thread so that you don't have to design your service to be thread-safe.
Using AIDL
AIDL (Android Interface Definition Language) performs all the
work to decompose objects into primitives that the operating system can
understand and marshall them across processes to perform IPC. The previous
technique, using a Messenger, is actually based on AIDL as its
underlying structure. As mentioned above, the Messenger creates a queue of all the
client requests in a single thread, so the service receives requests one at a
time. If, however, you want your service to handle multiple requests
simultaneously, then you can use AIDL directly. In this case, your service must
be capable of multi-threading and be built thread-safe.
To use AIDL directly, you must create an .aidl file
that defines the programming interface. The Android SDK tools use this file to
generate an abstract class that implements the interface and handles IPC, which
you can then extend within your service.
Note: Most applications should not use
AIDL to create a bound service, because it may require multithreading
capabilities and can result in a more complicated implementation. As such, AIDL
is not suitable for most applications and this document does not discuss how to
use it for your service. If you're certain that you need to use AIDL directly,
see the AIDL document.
Extending the Binder class
If your service is
used only by the local application and does not need to work across processes,
then you can implement your ownBinder class that provides your client
direct access to public methods in the service.
Note: This works only if the client and service are in the same
application and process, which is most common. For example, this would work
well for a music application that needs to bind an activity to its own service
that's playing music in the background.
Here's how to set it up:
1.
In your service,
create an instance of Binder that either:
·
contains public
methods that the client can call
·
returns the current Service instance, which has public
methods the client can call
·
or, returns an
instance of another class hosted by the service with public methods the client
can call
3.
In the client, receive
the Binder from the onServiceConnected() callback method and
make calls to the bound service using the methods provided.
Note: The reason the service and client must
be in the same application is so the client can cast the returned object and
properly call its APIs. The service and client must also be in the same
process, because this technique does not perform any marshalling across
processes.
For example, here's a service that provides clients access to methods in the
service through a Binder implementation:
public class
LocalService extends Service {
//
Binder given to clients
private
final IBinder mBinder = new LocalBinder();
//
Random number generator
private
final Random mGenerator = new Random();
/**
*
Class used for the client Binder. Because we know this service always
*
runs in the same process as its clients, we don't need to deal with IPC.
*/
public
class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can
call public methods
return LocalService.this;
}
}
@Override
public
IBinder onBind(Intent intent) {
return mBinder;
}
/**
method for clients */
public
int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
The LocalBinder provides
the getService() method for clients to retrieve the current instance
of LocalService. This allows clients to call public methods in the
service. For example, clients can call getRandomNumber() from the
service.
Here's an activity that binds to LocalService and calls getRandomNumber() when
a button is clicked:
public class
BindingActivity extends Activity {
LocalService mService;
boolean
mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/**
Called when a button is clicked (the button in the layout file attaches to
*
this method with the android:onClick attribute) */
public
void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang,
then this request should
// occur in a separate thread to avoid slowing down the
activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num,
Toast.LENGTH_SHORT).show();
}
}
/**
Defines callbacks for service binding, passed to bindService() */
private
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get
LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
The above sample shows
how the client binds to the service using an implementation of ServiceConnection and theonServiceConnected() callback. The next
section provides more information about this process of binding to the service.
Note: The example above doesn't explicitly unbind from the service,
but all clients should unbind at an appropriate time (such as when the activity
pauses).
For more sample code, see the LocalService.java class and the LocalServiceActivities.java class in ApiDemos.
Using a Messenger
Compared to AIDL
When you need to
perform IPC, using a Messenger for your interface is simpler
than implementing it with AIDL, because Messengerqueues all calls to the service,
whereas, a pure AIDL interface sends simultaneous requests to the service,
which must then handle multi-threading.
For most applications, the service doesn't need to perform multi-threading, so
using a Messenger allows the service to handle
one call at a time. If it's important that your service be multi-threaded, then
you should use AIDL to define your interface.
If you need your service to communicate with remote processes, then you can use
a Messenger to provide the interface for
your service. This technique allows you to perform interprocess communication
(IPC) without the need to use AIDL.
Here's a summary of how to use a Messenger:
·
The service implements
a Handler that receives a callback for each
call from a client.
·
Clients use the IBinder to instantiate the Messenger (that references the service's Handler), which the client uses to send Message objects to the service.
In this way, there are
no "methods" for the client to call on the service. Instead, the
client delivers "messages" (Message objects) that the service
receives in its Handler.
Here's a simple example service that uses a Messenger interface:
public class
MessengerService extends Service {
/** Command
to the service to display a message */
static
final int MSG_SAY_HELLO = 1;
/**
*
Handler of incoming messages from clients.
*/
class
IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!",
Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
*
Target we publish for clients to send messages to IncomingHandler.
*/
final
Messenger mMessenger = new Messenger(new IncomingHandler());
/**
*
When binding to the service, we return an interface to our messenger
*
for sending messages to the service.
*/
@Override
public
IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding",
Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
Notice that the handleMessage() method in the Handler is where the service receives the
incoming Message and decides what to do, based on
the what member.
All that a client needs to do is create a Messenger based on the IBinder returned by the service and send
a message usingsend(). For example, here's a simple activity
that binds to the service and delivers the MSG_SAY_HELLO message to
the service:
public class
ActivityMessenger extends Activity {
/**
Messenger for communicating with the service. */
Messenger mService = null;
/** Flag
indicating whether we have called bind on the service. */
boolean
mBound;
/**
*
Class for interacting with the main interface of the service.
*/
private
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service)
{
// This is called when the connection with the service has
been
// established, giving us the object we can use to
// interact with the service. We are communicating
with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has
been
// unexpectedly disconnected -- that is, its process
crashed.
mService = null;
mBound = false;
}
};
public
void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what'
value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0,
0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
BINDING TO A SERVICE
Application components
(clients) can bind to a service by calling bindService(). The Android system then calls
the service'sonBind() method, which returns an IBinder for interacting with the service.
The binding is asynchronous. bindService() returns immediately and
does not return the IBinder to the client. To receive theIBinder, the client must create an instance of ServiceConnection and pass it to bindService(). The ServiceConnectionincludes a callback method
that the system calls to deliver the IBinder.
Note: Only activities, services, and content providers can bind to
a service—you cannot bind to a service from a broadcast
receiver.
So, to bind to a service from your client, you must:
1.
Implement ServiceConnection.
Your implementation must override two callback methods:
The system calls this to deliver the IBinder returned by the service's onBind() method.
The Android system calls this when the
connection to the service is unexpectedly lost, such as when the service has
crashed or has been killed. This is not called when the client
unbinds.
3.
When the system calls
your onServiceConnected() callback method, you
can begin making calls to the service, using the methods defined by the
interface.
4.
To disconnect from the
service, call unbindService().
When your client is destroyed, it will unbind from the service, but you should
always unbind when you're done interacting with the service or when your
activity pauses so that the service can shutdown while its not being used.
(Appropriate times to bind and unbind is discussed more below.)
For example, the
following snippet connects the client to the service created above by extending the Binder class, so all it must do
is cast the returned IBinder to the LocalService class
and request the LocalService instance:
LocalService mService;
private
ServiceConnection mConnection = new ServiceConnection() {
//
Called when the connection with the service is established
public
void onServiceConnected(ComponentName className, IBinder service) {
// Because we have bound to an explicit
// service that is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
//
Called when the connection with the service disconnects unexpectedly
public
void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "onServiceDisconnected");
mBound = false;
}
};
Intent intent = new
Intent(this, LocalService.class);
bindService(intent,
mConnection, Context.BIND_AUTO_CREATE);
·
The first parameter of bindService() is an Intent that explicitly names the service
to bind (thought the intent could be implicit).
Additional notes
Here are some
important notes about binding to a service:
· You should always trap DeadObjectException exceptions, which are
thrown when the connection has broken. This is the only exception thrown by
remote methods.
· Objects are reference
counted across processes.
· You should usually
pair the binding and unbinding during matching bring-up and tear-down moments
of the client's lifecycle. For example:
· If you only need to
interact with the service while your activity is visible, you should bind
during onStart() and unbind during onStop().
· If you want your
activity to receive responses even while it is stopped in the background, then
you can bind duringonCreate() and unbind during onDestroy(). Beware that this implies that
your activity needs to use the service the entire time it's running (even in
the background), so if the service is in another process, then you increase the
weight of the process and it becomes more likely that the system will kill it.
Note: You should usually not bind
and unbind during your activity's onResume() and onPause(), because these callbacks occur at
every lifecycle transition and you should keep the processing that occurs at
these transitions to a minimum. Also, if multiple activities in your
application bind to the same service and there is a transition between two of
those activities, the service may be destroyed and recreated as the current
activity unbinds (during pause) before the next one binds (during resume).
(This activity transition for how activities coordinate their lifecycles is
described in the Activitiesdocument.)

Figure 1. The lifecycle for a service that is
started and also allows binding.
When a service is unbound from all clients, the Android system destroys it
(unless it was also started with onStartCommand()).
As such, you don't have to manage the lifecycle of your service if it's purely
a bound service—the Android system manages it for you based on whether it is
bound to any clients.
However, if you choose to implement the onStartCommand() callback
method, then you must explicitly stop the service, because the service is now
considered to be started. In this case, the service runs until the
service stops itself with stopSelf() or
another component calls stopService(),
regardless of whether it is bound to any clients.
Additionally, if your service is started and accepts binding, then when the
system calls your onUnbind() method,
you can optionally return true if you would like to receive a call to onRebind() the
next time a client binds to the service (instead of receiving a call toonBind()). onRebind() returns
void, but the client still receives the IBinder in
its onServiceConnected() callback.
Below, figure 1 illustrates the logic for this kind of lifecycle.
Example
ServicesDemo
package com.example;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ServicesDemo extends Activity implements OnClickListener {
private static final String TAG = "ServicesDemo";
Button buttonStart, buttonStop;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
buttonStart = (Button) findViewById(R.id.buttonStart);
buttonStop = (Button) findViewById(R.id.buttonStop);
buttonStart.setOnClickListener(this);
buttonStop.setOnClickListener(this);
}
public void onClick(View src) {
switch (src.getId()) {
case R.id.buttonStart:
Log.d(TAG, "onClick: starting srvice");
startService(new Intent(this, MyService.class));
break;
case R.id.buttonStop:
Log.d(TAG, "onClick: stopping srvice");
stopService(new Intent(this, MyService.class));
break;
}
}
}
MyService
package com.example;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class MyService extends
Service {
private static final String TAG =
"MyService";
MediaPlayer player;
@Override
public IBinder onBind(Intent intent)
{
return null;
}
@Override
public void onCreate() {
Toast.makeText(this, "My
Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
player = MediaPlayer.create(this,
R.raw.mai);
player.setLooping(false); // Set
looping
}
@Override
public void onDestroy() {
Toast.makeText(this, "My
Service Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
player.stop();
}
@Override
public void onStart(Intent intent,
int startid) {
Toast.makeText(this, "My
Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
player.start();
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example" android:versionCode="1" android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".ServicesDemo" 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:enabled="true" android:name=".MyService" />
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="Services Demo" android:gravity="center" android:textSize="20sp" android:padding="20dp"/>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/buttonStart" android:text="Start"></Button>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Stop" android:id="@+id/buttonStop"></Button>
</LinearLayout>
http://www.javabeat.net/articles/252-creating-services-in-android-1.html