Android Service Tutorial
2013-02-26 10:21
204 查看
Lars Vogel
Version 2.5Copyright © 2011, 2012, 2013 Lars Vogel
05.01.2013
Revision History | |||
---|---|---|---|
Revision 0.1 | 07.03.2011 | Lars Vogel | created |
Revision 0.2 - 2.5 | 08.03.2011 - 05.01.2013 | Lars Vogel | bug fixed and enhancements |
This tutorial describes how to create and consume Android services. It is based on Eclipse 4.2, Java 1.6 and Android 4.2.
Table of Contents
1. Android Services
1.1. Service1.2. Android Platform Service1.3. Defining new services
2. Defining services
2.1. Declaring own services2.2. Running a Services in its own process2.3. When to run a service in a separate process?2.4. Intent Services
3. Broadcast receiver4. Starting services
4.1. Start a service4.2. Stopping a service4.3. Binding between activities and local services4.4. Starting services regulary via AlarmManager
5. Communicating with Services
5.1. Activity binding to local service5.2. Using receiver5.3. AIDL for services in a different process5.4. Sending Intent data and bundle to the services
5.5. Handler and Messenger
6. Tutorial: Using IntentService
7. Tutorial: Define and consume local service8. Thank you
9. Questions and Discussion10. Links and Literature
10.1. Source Code10.2. Android Resources10.3. vogella Resources
1. Android Services
1.1. Service
A service is a component which runs in the background, without direct interaction with the user. The Android platform provides and runs predefined system services and every Android application can use them, given the right permissions.An Android application can, in addition to consuming the existing Android platform services, define and use new
services.
1.2. Android Platform Service
The Android platform provides pre-defined services, usually exposed via a specific Manager class. Access to them can be gained via thegetSystemService()method.
1.3. Defining new services
Every Android application can define and start new servicesIf you use asynchronous processing in activities or
fragments the corresponding threads are still connected to the life-cycle of the corresponding
activity. The Android system may decide to terminate them at any point in time.
Services run with a higher priority than inactive or invisible
activities and therefore it is less likely that the Android system terminates them.
Defining your own services allows you to design very responsive applications. You can fetch the application via a
service and once the application is started by the user, it can present fresh data to the user.
2. Defining services
2.1. Declaring own services
A service needs to be declared in theAndroidManifest.xmland the implementing class must extend the
Serviceclass or one of its subclasses. The following code shows an example for a
service declaration and its 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; } }
A service runs by default in the same process as the application. in its own thread.
Therefore you need to use asynchronous processing in the
service to to perform resource intensive tasks in the background.
Serviceswhich run in the process of the application are sometimes called local
services.
2.2. Running a Services in its own process
You can also specify that your Serviceruns in a separate process via the
android:process=":process_description"attribute.
<service android:name="WordService" android:process=":my_process" android:icon="@drawable/icon" android:label="@string/service_name" > </service>
The colon prefix before the name tells Android that the
Serviceis private to its declaring application. If the colon is not used the
Servicewould be a global process and can be used by other Android applications.
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.
Even if the service runs in its own process you need to use asynchronous processing to perform network access because Android does not allow network access in the main thread of a process.
2.3. When to run a service in a separate process?
Running a service in its own process gives it its own memory address space and a garbage collector of the virtual machine in this process does not affect the application process.Application rarely need to run a service in its own process. Running a services in its own process make the communication of the other Android components and the
service harder to implement.
If you want to make a service to other Android application available, they must run in their own process.
2.4. Intent Services
You can also extend theIntentServiceclass for your service implementation.
The
IntentServiceis used to perform a certain task in the background. Once done, the instance of
IntentServiceterminate itself automatically. Examples for its usage would be to download a certain resources from the Internet.
The
IntentServiceclass offers the
onHandleIntent()method which will be asynchronously called by the Android system.
3. Broadcast receiver
For an introduction intoBroadcastReceiverplease see
Android Broadcast Receiver tutorial .
4. Starting services
4.1. Start a service
An Android component (service, receiver, activity) can start and trigger aservice via the
startService(intent)method. This method call starts the
service if it is not running.
Intent service = new Intent(context, MyService.class); context.startService(service);
If the service started the
onCreate()method is called.
Once the service is started the method call to start the
service triggers
startService(intent)method in the
service. It passes in the
Intentfor the
startService(intent)call.
If
startService(intent)is called while the
service is running, its
onStartCommand()is also called. Therefore your
service needs to be prepared that
onStartCommand()can be called several times. This method is called in the main user interface thread therefore it cannot be called simultaneously from two different threads.
Alternatively to
startService(intent)you can also start a
service via the
bindService()method call. This allows you to communicate directly with the
service.
4.2. Stopping a service
You stop a service via thestopService()method. No matter how frequently you started the
service with
startService(intent)a call to
stopService()stops it.
A service can stop itself by calling the
stopSelf()method.
4.3. Binding between activities and local services
If the activity wants to interact with theservice it can use the
bindService()method to start the
service.
This method requires as parameter a
ServiceConnectionobject which allows to connect to the
service. In the service the
onBind()method is called. This method returns a
IBinderobject to the
ServiceConnection.
This
IBinderobject can be used by the activity to communicate with the
service.
Afterwards the binding was done the
onStartCommand()method is called with the
Intentdata provided by the activity.
startService()also allows you to provide a flag which determines the restart behavior of the services.
Service.START_STICKYis used for services which are explicit started or stopped. If these services are terminated by the Android system, they are restarted if sufficient resource are available again.
Services started with
Service.START_NOT_STICKYare not automatically restarted if terminated by the Android system.
4.4. Starting services regulary 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 aTimerTaskin the service to ensure that it is executed on a regular basis.
For correct scheduling of the
Serviceuse the
AlarmManagerclass. The following code demonstrates how to do this.
Intent intent = new Intent(this, MyService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
// Start every 30 seconds
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 30*1000, pintent);
5. Communicating with Services
There are several way for an activity to communicate with anservice and vice versa. This section dicusses the different ways and gives recommendation which to use.
5.1. Activity binding to local service
If the Serviceis started in the same process as the
Activity, the
Activitycan directly bind to the service. This is a relatively simple and efficient way to communication.
5.2. Using receiver
You can also use dynamically registered receivers for the communication. For example youractivity can dynamically register a
receiver and the service sends outs corresponding events.
5.3. 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) as the data needs to be send between different processes. For this you need to create a AIDL file which looks similar toan Java interface but ends with the
.aidlfile extension and is only allowed to extend other AIDL files.
This approach is required if your service should be provided to other applications, otherwise you should prefer a local service.
5.4. Sending Intent data and bundle to the services
The service receives data from the starting Android component and can use this data.5.5. Handler and Messenger
If the service should be communicating back to the activity it can receive an object of typeMessengervia the
Intentdata it receives from the
Activity. If the
Messengeris bound to a
Handlerin the activity the
servicecan send objects of type
Messageto the
activity.
A
Messengeris parcelable, which means it can be passed to another process and you can use this object to send
Messagesto the
Handlerin the
activity.
Messengerprovides also the method
getBinder()which allows to pass a
Messengerto the
activity. The
Activitycan therefore send
Messagesto the service.
6. Tutorial: Using IntentService
The following example demonstrates how to use the IntentServiceclass to download a file from the Internet. Once done the
IntentServicewill use an instance of the
Messengerclass to inform the
Activitywhich started the service about the location of the downloaded file.
Create a new project called de.vogella.android.intentservice.download with a
Activitycalled 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.xmllayout 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="Button" /> </LinearLayout>
Change
MainActivityto 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 backMessenger messenger = new Messenger(handler);
intent.putExtra("MESSENGER", messenger);
intent.setData(Uri.parse("http://www.vogella.com/index.html"));
intent.putExtra("urlpath", "http://www.vogella.com/index.html");
startService(intent);
}
}
If you run your example and press the button, the download should be performed by the
Serviceand once done the
Activityshould show a Toast with the file name.
7. Tutorial: Define and consume local service
The following chapter demonstrates how to create and consume a service from anactivity. The service startes at boot time and periodically fetch data. The
activitybinds itself to the service and use connection to communicate with the service.
Create a new project called de.vogella.android.ownservice.local with an
Activitycalled MainActivity.
Create the
LocalWordServiceclass.
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() { 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, i,
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 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="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="match_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
Activityclass to the following code.
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(); } } }
8. Thank you
Please help me to support this article:9. Questions and Discussion
Before posting questions, please see thevogella FAQ. If you have questions or find an error in this article please use the
www.vogella.com Google Group. I have created a short list
how to create good questions which might also help you.
10. Links and Literature
10.1. Source Code
Source Code of Examples10.2. Android Resources
Android Development TutorialAndroid ListView and ListActivity
Android Location API and Google Maps
Android Intents
Android and Networking
Android Background processing with Threads and Asynchronous Task
Remote Messenger Service from Google
10.3. vogella Resources
vogella TrainingAndroid and Eclipse Training from the vogella team
Android Tutorial
Introduction to Android Programming
GWT Tutorial
Program in Java and compile to JavaScript and HTML
Eclipse RCP Tutorial
Create native applications in Java
JUnit Tutorial
Test your application
Git Tutorial
Put everything you have under distributed version control system
相关文章推荐
- Android Service - Tutorial
- Android Service and Broadcast Receiver Tutorial
- Android Service完全解析,关于服务你所需知道的一切(上)
- Android Service全解(三)之 Foreground Service(转)
- android 服务service
- Android Service与Activity之间通信的几种方式
- Android启动流程分析(十) action的执行和service的启动
- Android IntentService完全解析 当Service遇到Handler
- Android中Service与Thread的区别
- I.MX6 android BatteryService jni hacking
- Android-工作在后台-Service
- Android Service随笔
- Android WifiService的启动流程分析
- Android 之ActivityThead、ActivityManagerService 与activity的管理和创建
- Android SensorService启动流程(一)
- android四大组件--Service简介
- android5.1BatteryService深入分析
- android四大组建之Service
- android am 启动activity service or broadcast及参数传递
- android Service