1.Services
A Service is an application component that can perform long-running operations in the background and does not provide a user interface.
A service can essentially take two forms:
<1>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.
<2>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.
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.
2. The Basic
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:
<1>onStartCommand()
The system calls this method when another component, such as an activity, requests that the service be started, by calling
startService()
. 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()
.
<2>onBind()
The system calls this method when another component wants to bind with the service (such as to perform RPC), by calling
bindService()
. 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,
<3>onCreate()
<4>onDestroy()
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.
3. Declaring a service in the manifest
Like activities (and other components), you must declare all services in your application‘s manifest file.
To ensure your app is secure, always use an explicit intent when starting or binding your Service
and do not declare intent filters for
the service.
4. Creating a started Service
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,
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.
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:
<1>IntentService
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.
//IntentServiceTest package com.example.intentservicedemo; import android.app.IntentService; import android.content.Intent; public class IntentServiceTest extends IntentService { /** * A constructor is required, and must call the super IntentService(String) * constructor with a name for the worker thread. */ public IntentServiceTest() { //be sure to use empty constructor!!!!! super("IntentServiceTest"); } /** * 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. String action = intent.getExtras().getString("param"); if (action.equals("oper1")) { System.out.println("Operation1"); }else if (action.equals("oper2")) { System.out.println("Operation2"); } try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }
//Mainactivity package com.example.intentservicedemo; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //可以启动多次,每启动一次,就会新建一个work thread,但IntentService的实例始终只有一个 //Operation 1 Intent startServiceIntent = new Intent("com.test.intentservice"); Bundle bundle = new Bundle(); bundle.putString("param", "oper1"); startServiceIntent.putExtras(bundle); startService(startServiceIntent); //Operation 2 Intent startServiceIntent2 = new Intent("com.test.intentservice"); Bundle bundle2 = new Bundle(); bundle2.putString("param", "oper2"); startServiceIntent2.putExtras(bundle2); startService(startServiceIntent2); } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.intentservicedemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".IntentServiceTest"> <intent-filter > <action android:name="com.test.intentservice"/> </intent-filter> </service> </application> </manifest>
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.)
<2>Services
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.
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.
//MainActivity package mirror.android.servicetest; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startService(new Intent("servicetest")); } }
//ServiceTest package mirror.android.servicetest; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class ServiceTest extends Service { @Override public IBinder onBind(Intent intent) { // We don‘t provide binding, so return null return null; } @Override public void onDestroy() { super.onDestroy(); } @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. super.onCreate(); Log.d("Service_Test","started"); try { Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); } Log.d("Service_Test","Sleep ends"); } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="mirror.android.servicetest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".ServiceTest"> <intent-filter > <action android:name="servicetest"/> </intent-filter> </service> </application> </manifest>
The appliction will be blocked, and will be warned "The appliction will do too much work ....", because we need to create a new thread,!!!!!!
5. Starting a Service
You can start a service from an activity or other application component by passing an Intent
(specifying the service to start) to startService()
.
The Android system calls the service‘s onStartCommand()
method and passes it the Intent
. (You should never call onStartCommand()
directly.)
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.
6. Stopping a service
the service must stop itself by calling stopSelf()
or another component can stop it by calling stopService()
.
It‘s important that your application stops its services when it‘s done working, to avoid wasting system resources and consuming battery
power.
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.
7. Sending Notifications to the user
A service can notify user of events using Toast Notifications or Status Bar Notification
8. Managing the lifecycle of a service