服务是一个应用组件,可以在后执行耗时的操作,不提供一个用户界面。(因为不提供界面,所以可以耗时执行,和活动最大的不同)。另一个应用组件可以启动一个服务,服务会继续在后台运行及时用户切换到另一个应用(和活动不一样,那么生命周期就有不同了)。此外,一个组件可以绑定一个服务和他进行交互甚至执行进程间通信(interprocess communication (IPC))。举例,一个服务可能处理网络事务,播放音乐,执行文件或者和一个content provider交互,所有都是在后台。
一个服务本质上接收两种格式:
Started
当一个组件(比如活动)调用startService的时候 ,一个服务启动。一旦启动,一个服务可以在后台无限期的运行,即使启动他的组件被销毁了。通常,一个启动的服务执行一个单一的操作,不给调用者返回一个结果。举例,服务可能通过网络下载或者更新文件。当操作完成,服务应该自己停止自己。
Bound
当一个应用组件调用bindService绑定到他上面服务被bound。一个bound的服务,提供一个客户端服务器界面,允许组件和这个服务交互,发送请求,得到结果,甚至通过进程间通信实现这些。一个bound服务,只有在另一个组件绑定到他上面才会执行。多个组件可以马上绑定到这个服务,但是当他们都解绑了,服务被销毁。
虽然这个文件通常独立的讨论这两种服务,我们的服务可以以这两种方式工作。可以被启动(无限期执行)而且允许绑定。主要就看我们是不是实现一对回调方法:onStartCommand允许组件启动他,onBind允许绑定。
无论我们的程序是否启动,bound,或者所有,任何应用组件都可以使用这个服务(即使从一个分开的程序),任何组件也可以以同样的方式使用活动,通过intent启动他。然后,我们可以声明服务为私有的,在manifest文件中,阻止其他程序访问他。在下文会讲吧。
小心:一个服务在他的宿主进程的主线程中运行,服务不创建他自己的线程,不在一个独立的进程中运行(除非我们另外指定)。这就意味着,如果我们的服务去做任何CPU集中的工作或者阻塞动作(比如mp3播放或网络工作),我们应该在服务中新建一个线程做这些工作。通过使用独立的线程,我们可以降低ANR错误的风险,并且我们的主线程可以一直保持献身于用户交互使用活动。
The Basics
要创建一个服务,我们必须创建一个Service的子类(或者一个应经存在的子类)。在我们的实现中,如果有需要,重写一些回调方法处理服务生命周期的主要方便和为组件提供一个绑定到服务的机制。最重要的可以重写的回调方法如下:
onStartCommand()
系统调用这个方法当另一个组件,比如活动,通过调用startService要求这个服务启动。一旦方法执行,服务被启动,可以在后台无限期运行。如果我们实现这个方法,当服务的工作完成后是我们的责任去停止服务。通过调用 stopSelf() 或 stopService()(如果仅仅想提供绑定,不需要实现这个方法,很明显啊,这是start用的)
onBind()
系统调用这个方法当另一个组件调用BingService希望绑定到这个服务上(比如执行RPC)。在方法的实现中,我们必须提供一个接口,客户端用来和服务交流,通过返回一个LBinder。必须总是实现这个方法,如果不允许绑定,应该返回null。
onCreate()
当服务第一次创建的时候系统调用他,执行一次性的设置程序(before it calls either onStartCommand() or onBind() 在??前)。如果服务应经运行了,这个方法不会调用。
onDestroy()
系统调用这个方法当服务不在被使用并且将要被销毁。我们的服务应该实现这个方法去清理任何资源,比如线程,注册的监听器,接收器等。这是服务接收的最后一个调用的方法。
如果一个组件通过调用startService启动服务(导致一个onStartCommand调用,然后这个服务保持运行,直到通过stopSelf停止或者另一个组件调用stopService停止他。
如果一个组件调用bindService去创建一个服务(onStartCommand不会调用),然后这个服务只有在组件绑定上才执行。一旦服务和所以的客户端解除绑定,系统应该销毁他。
安卓系统会强制停止一个服务只有当内存很低,必须为用户操作的活动恢复系统资源的时候。如果服务绑定到用户聚焦的活动上,他不太可能比杀死,如果服务被声明run in the foreground (一会讲),他几乎不会被杀死。否则,一个服务被启动,长时间执行,系统会降低他在后台任务的位置随着时间推移,服务会变得很容易被杀死,如果我们的服务启动,我们必须很优雅的设计去处理系统的重启。如果系统杀死我们的服务,一旦资源可用会重启服务(虽然这个也依靠我们从onStartCommand返回的值,一会讲)。
For more information about when the system might destroy a service, see the Processes and Threading document.
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.
一个服务仅仅是一个可以后天运行的组件,即使用户不和我们的应用交互。这样,我们应再只有需要的时候才创建一个服务。
如果需要在main线程之外执行任务,但是只有在用户和程序交互的时候,我们可能仅仅创建一个新线程而不是一个服务。举例,想播放音乐,但是只有活动运行的时候才愿意,可以在onCreate中创建一个线程,在onStart中开始执行,然后在onStop停止。
也可以考虑使用 AsyncTask or HandlerThread,代替传统线程。See the Processes and Threading document for more information about threads.
记住,如果使用一个服务,他仍然默认在主线程中运行,所以如果执行密集和阻塞操作,应该仍然创建一个新的线程。
下面开始讲,如何创建每种类型的服务和从其他应用组件如何使用它。
Declaring a service in the manifest
和活动(其他组件一样),必须在应用的manifest文件中定义所以的服务。
在<application>元素中添加一个<service>元素作为子元素,如下:
<manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
...
</application>
</manifest>
可以在<service>元素中包含其他元素定义属性,不日启动这个服务的权限和这个服务应该运行的进程。Android:name 是唯一必须的属性,指定了服务的类名。一旦发布应用,不应该改变这个名称。因为这样做,打破显式的意图或者绑定这个服务的代码。查看blog Things That Cannot Change) 。
为了确保app的安全,总是使用显式意图启动和绑定服务,不要给服务声明intent过滤器。
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. If it's critical that you allow for some amount of ambiguity as to which service starts, you can supply intent filters for your services and exclude the component name from the Intent, but you then must set the package for the intent with setPackage(), which provides sufficient disambiguation for the target service.
此外,设置 android:exported 属性为false阻止其他程序启动我们的服务。这样可以有效的阻止其他程序启动我们的服务,即使使用显式意图。(和活动很像啊).
Creating a Started Service
一个被启动的服务是另一个组件通过调用startService启动的,导致服务调用他的onStartCommand方法。
当一个服务是被启动,它的生命周期独立于启动他的组件,服务可以在后台无限的运行,及时启动他的组件被销毁了。因此,服务应该在任务完成的时候调用stopSelf停止或者其他组件调用stopService停止。
一个应用组件,比如一个活动可以通过调用startService启动服务,传递说明这个服务的和包含这个服务使用的信息的intent。服务在onStartCommand方法中接收这个Intent。
打个比方,假设一个活动需要保存一些数据到线上的数据库。活动可以启动一个同伴服务,通过传递一个inent给startService传送给服务需要保存的数据。服务在onStartCommand接收这个Intent,连接网络,执行数据库事务。当事务结束,服务停止自己,然后被销毁。
小心:默认,一个服务在和主线程所在的进程中执行。所以,如果服务执行集中的或者阻塞动作当用户和应用程序的活动交互,服务会减缓活动表现。为了避免影响应用的表现,应该在服务中启动一个新线程。
习惯上,有两个类可以实现去创建一个被启动的服务:
Service
所有服务的基础类。当继承这个类,很重要去创建一个新的线程去执行所以的服务操作,因为服务默认使用应用的主线程,可能会减缓其他活动的执行。
IntentService
这是Service的一个子类,使用工作线程处理所有的启开始请求,一次一个。如果不要求服务同时处理多个请求,这是最好的选择。我们要做的就是实现onHandleIntent,为每一个开始请求接收Intent,这样就可以做后台工作。
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.
Extending the IntentService class
因为大多数的被启动的服务不需要同时处理多个请求(实际上多线程很危险)。这时候应该最好使用IntentService。
IntentService做了下面的事:
The IntentService does the following:
• 创建一个默认的工作线程执行所以传递给onStartCommand的intents独立于应用的主线程(新的线程了,所以不会干扰,那还说我自己要新启线程,应该是直接Service需要)
• 创建一个工作序列,一次传递一个intent给onHandleIntent实现,所以永远不用担心多线程
• 所有的开启请求被处理完之后停止服务,所以永远不用调用stopSelf
• 提供onBind的默认实现,返回null
• 提供onStartCommand的默认实现,这个方法发送intent给工作序列,然后发送intent给onHandleIntent实现。
所有这些加起来,我们需要做的就是实现onHandleIntent,执行客户端提交的任务(虽然,还需要提供一个小的构造器给服务,下面会看到)
public class HelloIntentService extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* 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) {
}
}
}
}
}
所有需要做的就是:一个构造器和一个onHandleIntent的实现
如果决定重写其他的回调方法,比如onCreate,onStartCommand,onDe,确定调用父类的实现,这样IntentService可以妥善处理工作线程的生命。
举例,onStartCommand方法必须返回默认的实现(这是intent如何被交付给onHandleIntent)。
@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);
}
除了onHandleIntent,唯一不需要调用的父类方法是onBind(但是你仅仅需要实现服务允许绑定)。
在下面会看到Service实现的同样的服务,会有更多的代码,但是如果要同时处理多个开始请求是合适的。
Extending the Service class
上面展示的,使用IntentService让我们实现一个启动服务非常简单。如果,然而,需要服务执行多线程(而不是处理启动请求通过一个工作序列),然后可以继承Service类去处理每一个Intent。
作为对比,下面的代码是一个Service类的实现,执行和上面IntentService一样的工作。那就是,为每一个启动请求,他使用一个工作线程去执行这个任务,一次只处理一个请求。
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();
}
}
然后,因为处理每个调用给onStartCommand,可以同时执行多个请求(和上面什么区别,没懂?)。这个例子没有这做,但是如果想这么做,为每一个请求创建一个新线程(就是新建一个线程,上面的例子没有新建一个线程,多个线程怎么停啊,这是个问题??),然后立马执行他们(而不是等待上一个执行完毕)
多个停止是,为每一个request设置一个Id,然后如果这个ID和正在执行的不一致就不会停止,上面的例子不行啊,多个线程,多次调用这个stop,万一有一个成功呢,还需要研究,怎么停止,下文也没讲清楚啊。
注意到,onStartCommand方法必须返回一个整数,这个整数是一个数值描述系统应该如何继续这个服务在这个事件当系统杀死他(上面调理,对于Intentservice默认的实现帮我们处理,虽然我们可以修改他)。onStartCommand的返回值必须的下面当中的一个常量:
START_NOT_STICKY
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.
START_STICKY
If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), but do not redeliver 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.
START_REDELIVER_INTENT
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.
Stopping a service
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.
说是这个ID是建立在最新的一个请求的,也就是说前面的请求的id和传给onStartCommand方法的ID不一致,只要有新请求,id就变,会不会有开始只有一个执行,然后其他等到这个执行了还没执行,不就stop了,呵呵
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().
Creating a Bound Service
一个绑定服务是一个服务允许应用组件通过调用bindService绑定到他上面创建一个长期存在的关系(通常不允许组件调用startService启动他)。
当我们想和来自程序中的活动或者其他组件的服务交互或者通过进程通信暴露一些应用程序的功能给其他应用,应该创建一个绑定服务。
(1)要创建一个绑定服务,必须实现onBind方法,返回一个定义和服务通信的接口的IBinder(2)其他应用组件然后可以调用bindService(这个方法有个ServiceConnection参数,需要设置一些)方法获得这个接口,开始调用服务上的方法。
要创建一个绑定服务,第一件要做的事就是定义指定客户端如何跟服务通信的接口。(一般我们的是不在服务中创建一个Binder(实现IBinder接口)的实例)。这个接口必须是一个IBinder的实现,同时是服务必须在onBind回调方法返回的。一旦客户端收到这个IBinder,可以通过那个接口和服务交互。
多个客户端可以同时绑定到一个服务。当一个客户端和服务执行完交互,调用unBindService去解绑。一旦没有客户端绑定到服务上,系统销毁这个服务。
有多种方式实现一个绑定服务,而且实现比启动的服务更复杂,所以这个绑定服务在独立的绑定服务文档讨论。
Managing the Lifecycle of a Service
服务的生命周期和活动很像。然而,更重要的是,我们应该更关注我们的服务如何创建和销毁,因为一个服务可以在用户不知道情况下在后台运行。
服务的生命周期重创建到销毁有这两个路劲:
• A started service
另一个组件调用startService()启动这个服务.服务然后在后台无限期运行,必须调用stopSelf停止自己。另一程序也可以调用stopService停止。当服务停止,系统销毁他。
• A bound service
当另一个组件(一个客户端)调用bindService的时候,服务被创建。客户端然后通过IBinder接口和服务通信。多个客户端可以绑定到同一个服务,当他们全部解绑,系统销毁这个服务(服务不需要自己停止)。
这两个路径不是完全分离的。那就是,可以绑定到一个已经由startSercie启动的服务。举例,一个后台音乐服务可以通过调用statService用一个确认要播放的音乐Intent启动。然后,可能当用户想执行一些控制在这个播放器或者得到当前歌曲的信息,一个活动通过调用bindService绑定到服务上。在这样的例子,stopService() or stopSelf() 不能停止服务直到所有的客户端解绑。(所有客户端解绑,应该也不停止服务吧,除非调用这个两个方法)
Implementing the lifecycle callbacks
和活动很像,一个服务有生命周期回调方法我们可以实现去监听服务的状态改变,在适合的实际执行工作。下面的骨架服务展示了每一个生命周期方法。
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
public void onCreate() {
// The service is being created
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The service is starting, due to a call to startService()
return mStartMode;
}
@Override
public IBinder onBind(Intent intent) {
// A client is binding to the service with bindService()
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// All clients have unbound with unbindService()
return mAllowRebind;
}
@Override
public void onRebind(Intent intent) {
// A client is binding to the service with bindService(),
// after onUnbind() has already been called
}
@Override
public void onDestroy() {
// The service is no longer used and is being destroyed
}
}
Note:不像活动的生命周期回来方法,不用调用父类的这些方法的实现。
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().
通过实现写方法,可以监听两个嵌套的服务生命周期循环。
• 服务的整个生命周期发生在onCreate被调用和onDestroy返回之间。项一个活动,服务在onCreate进行初始化设置,在onDestroy中释放所有资源。举例,一个音乐播放服务可以在onCreate中创建音乐播放的线程,然后在onDestroy中停止这个线程。
可以看到,onCreate()和 onDestroy()方法被所有服务调用,无论他们的由startService() 还是bindService()创建。
• 服务的活跃生命时间 从onStartCommand或者onBind开始。每个方法分别处理来自startService或者bindService传递的intent
如果服务是被启动,活跃生命周期随着整个生命周期结束而结束(服务仍然是活跃的,甚至在onStartCommand返回之后)。如果服务是绑定的,活跃生命时间随着onUnbind返回结束。
Note:虽然一个被启动的服务由stopSelf() or stopService()停止, 服务没有一个回调方法(没有onStop回调)。所以,除非服务绑定到一个客户端,否则当服务停止系统销毁他,onDestroy是被接收唯一的回调方法。
上图阐明了服务的典型的回调方法。虽然该图分离了由startService和bindService创建的服务,在心中铭记,任何服务,无论如何启动,可以潜在的允许客户端绑定他。所以,一个最初有onStartCommand方法(通过客户端调用startService)启动的服务,仍然可以接受一个onBind(当一个客户端调用bindService) bind 可以被启动吗,应该是不可以吧。
查看Bound Service更多。
一个服务本质上接收两种格式:
Started
当一个组件(比如活动)调用startService的时候 ,一个服务启动。一旦启动,一个服务可以在后台无限期的运行,即使启动他的组件被销毁了。通常,一个启动的服务执行一个单一的操作,不给调用者返回一个结果。举例,服务可能通过网络下载或者更新文件。当操作完成,服务应该自己停止自己。
Bound
当一个应用组件调用bindService绑定到他上面服务被bound。一个bound的服务,提供一个客户端服务器界面,允许组件和这个服务交互,发送请求,得到结果,甚至通过进程间通信实现这些。一个bound服务,只有在另一个组件绑定到他上面才会执行。多个组件可以马上绑定到这个服务,但是当他们都解绑了,服务被销毁。
虽然这个文件通常独立的讨论这两种服务,我们的服务可以以这两种方式工作。可以被启动(无限期执行)而且允许绑定。主要就看我们是不是实现一对回调方法:onStartCommand允许组件启动他,onBind允许绑定。
无论我们的程序是否启动,bound,或者所有,任何应用组件都可以使用这个服务(即使从一个分开的程序),任何组件也可以以同样的方式使用活动,通过intent启动他。然后,我们可以声明服务为私有的,在manifest文件中,阻止其他程序访问他。在下文会讲吧。
小心:一个服务在他的宿主进程的主线程中运行,服务不创建他自己的线程,不在一个独立的进程中运行(除非我们另外指定)。这就意味着,如果我们的服务去做任何CPU集中的工作或者阻塞动作(比如mp3播放或网络工作),我们应该在服务中新建一个线程做这些工作。通过使用独立的线程,我们可以降低ANR错误的风险,并且我们的主线程可以一直保持献身于用户交互使用活动。
The Basics
要创建一个服务,我们必须创建一个Service的子类(或者一个应经存在的子类)。在我们的实现中,如果有需要,重写一些回调方法处理服务生命周期的主要方便和为组件提供一个绑定到服务的机制。最重要的可以重写的回调方法如下:
onStartCommand()
系统调用这个方法当另一个组件,比如活动,通过调用startService要求这个服务启动。一旦方法执行,服务被启动,可以在后台无限期运行。如果我们实现这个方法,当服务的工作完成后是我们的责任去停止服务。通过调用 stopSelf() 或 stopService()(如果仅仅想提供绑定,不需要实现这个方法,很明显啊,这是start用的)
onBind()
系统调用这个方法当另一个组件调用BingService希望绑定到这个服务上(比如执行RPC)。在方法的实现中,我们必须提供一个接口,客户端用来和服务交流,通过返回一个LBinder。必须总是实现这个方法,如果不允许绑定,应该返回null。
onCreate()
当服务第一次创建的时候系统调用他,执行一次性的设置程序(before it calls either onStartCommand() or onBind() 在??前)。如果服务应经运行了,这个方法不会调用。
onDestroy()
系统调用这个方法当服务不在被使用并且将要被销毁。我们的服务应该实现这个方法去清理任何资源,比如线程,注册的监听器,接收器等。这是服务接收的最后一个调用的方法。
如果一个组件通过调用startService启动服务(导致一个onStartCommand调用,然后这个服务保持运行,直到通过stopSelf停止或者另一个组件调用stopService停止他。
如果一个组件调用bindService去创建一个服务(onStartCommand不会调用),然后这个服务只有在组件绑定上才执行。一旦服务和所以的客户端解除绑定,系统应该销毁他。
安卓系统会强制停止一个服务只有当内存很低,必须为用户操作的活动恢复系统资源的时候。如果服务绑定到用户聚焦的活动上,他不太可能比杀死,如果服务被声明run in the foreground (一会讲),他几乎不会被杀死。否则,一个服务被启动,长时间执行,系统会降低他在后台任务的位置随着时间推移,服务会变得很容易被杀死,如果我们的服务启动,我们必须很优雅的设计去处理系统的重启。如果系统杀死我们的服务,一旦资源可用会重启服务(虽然这个也依靠我们从onStartCommand返回的值,一会讲)。
For more information about when the system might destroy a service, see the Processes and Threading document.
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.
一个服务仅仅是一个可以后天运行的组件,即使用户不和我们的应用交互。这样,我们应再只有需要的时候才创建一个服务。
如果需要在main线程之外执行任务,但是只有在用户和程序交互的时候,我们可能仅仅创建一个新线程而不是一个服务。举例,想播放音乐,但是只有活动运行的时候才愿意,可以在onCreate中创建一个线程,在onStart中开始执行,然后在onStop停止。
也可以考虑使用 AsyncTask or HandlerThread,代替传统线程。See the Processes and Threading document for more information about threads.
记住,如果使用一个服务,他仍然默认在主线程中运行,所以如果执行密集和阻塞操作,应该仍然创建一个新的线程。
下面开始讲,如何创建每种类型的服务和从其他应用组件如何使用它。
Declaring a service in the manifest
和活动(其他组件一样),必须在应用的manifest文件中定义所以的服务。
在<application>元素中添加一个<service>元素作为子元素,如下:
<manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
...
</application>
</manifest>
可以在<service>元素中包含其他元素定义属性,不日启动这个服务的权限和这个服务应该运行的进程。Android:name 是唯一必须的属性,指定了服务的类名。一旦发布应用,不应该改变这个名称。因为这样做,打破显式的意图或者绑定这个服务的代码。查看blog Things That Cannot Change) 。
为了确保app的安全,总是使用显式意图启动和绑定服务,不要给服务声明intent过滤器。
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. If it's critical that you allow for some amount of ambiguity as to which service starts, you can supply intent filters for your services and exclude the component name from the Intent, but you then must set the package for the intent with setPackage(), which provides sufficient disambiguation for the target service.
此外,设置 android:exported 属性为false阻止其他程序启动我们的服务。这样可以有效的阻止其他程序启动我们的服务,即使使用显式意图。(和活动很像啊).
Creating a Started Service
一个被启动的服务是另一个组件通过调用startService启动的,导致服务调用他的onStartCommand方法。
当一个服务是被启动,它的生命周期独立于启动他的组件,服务可以在后台无限的运行,及时启动他的组件被销毁了。因此,服务应该在任务完成的时候调用stopSelf停止或者其他组件调用stopService停止。
一个应用组件,比如一个活动可以通过调用startService启动服务,传递说明这个服务的和包含这个服务使用的信息的intent。服务在onStartCommand方法中接收这个Intent。
打个比方,假设一个活动需要保存一些数据到线上的数据库。活动可以启动一个同伴服务,通过传递一个inent给startService传送给服务需要保存的数据。服务在onStartCommand接收这个Intent,连接网络,执行数据库事务。当事务结束,服务停止自己,然后被销毁。
小心:默认,一个服务在和主线程所在的进程中执行。所以,如果服务执行集中的或者阻塞动作当用户和应用程序的活动交互,服务会减缓活动表现。为了避免影响应用的表现,应该在服务中启动一个新线程。
习惯上,有两个类可以实现去创建一个被启动的服务:
Service
所有服务的基础类。当继承这个类,很重要去创建一个新的线程去执行所以的服务操作,因为服务默认使用应用的主线程,可能会减缓其他活动的执行。
IntentService
这是Service的一个子类,使用工作线程处理所有的启开始请求,一次一个。如果不要求服务同时处理多个请求,这是最好的选择。我们要做的就是实现onHandleIntent,为每一个开始请求接收Intent,这样就可以做后台工作。
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.
Extending the IntentService class
因为大多数的被启动的服务不需要同时处理多个请求(实际上多线程很危险)。这时候应该最好使用IntentService。
IntentService做了下面的事:
The IntentService does the following:
• 创建一个默认的工作线程执行所以传递给onStartCommand的intents独立于应用的主线程(新的线程了,所以不会干扰,那还说我自己要新启线程,应该是直接Service需要)
• 创建一个工作序列,一次传递一个intent给onHandleIntent实现,所以永远不用担心多线程
• 所有的开启请求被处理完之后停止服务,所以永远不用调用stopSelf
• 提供onBind的默认实现,返回null
• 提供onStartCommand的默认实现,这个方法发送intent给工作序列,然后发送intent给onHandleIntent实现。
所有这些加起来,我们需要做的就是实现onHandleIntent,执行客户端提交的任务(虽然,还需要提供一个小的构造器给服务,下面会看到)
public class HelloIntentService extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* 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) {
}
}
}
}
}
所有需要做的就是:一个构造器和一个onHandleIntent的实现
如果决定重写其他的回调方法,比如onCreate,onStartCommand,onDe,确定调用父类的实现,这样IntentService可以妥善处理工作线程的生命。
举例,onStartCommand方法必须返回默认的实现(这是intent如何被交付给onHandleIntent)。
@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);
}
除了onHandleIntent,唯一不需要调用的父类方法是onBind(但是你仅仅需要实现服务允许绑定)。
在下面会看到Service实现的同样的服务,会有更多的代码,但是如果要同时处理多个开始请求是合适的。
Extending the Service class
上面展示的,使用IntentService让我们实现一个启动服务非常简单。如果,然而,需要服务执行多线程(而不是处理启动请求通过一个工作序列),然后可以继承Service类去处理每一个Intent。
作为对比,下面的代码是一个Service类的实现,执行和上面IntentService一样的工作。那就是,为每一个启动请求,他使用一个工作线程去执行这个任务,一次只处理一个请求。
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();
}
}
然后,因为处理每个调用给onStartCommand,可以同时执行多个请求(和上面什么区别,没懂?)。这个例子没有这做,但是如果想这么做,为每一个请求创建一个新线程(就是新建一个线程,上面的例子没有新建一个线程,多个线程怎么停啊,这是个问题??),然后立马执行他们(而不是等待上一个执行完毕)
多个停止是,为每一个request设置一个Id,然后如果这个ID和正在执行的不一致就不会停止,上面的例子不行啊,多个线程,多次调用这个stop,万一有一个成功呢,还需要研究,怎么停止,下文也没讲清楚啊。
注意到,onStartCommand方法必须返回一个整数,这个整数是一个数值描述系统应该如何继续这个服务在这个事件当系统杀死他(上面调理,对于Intentservice默认的实现帮我们处理,虽然我们可以修改他)。onStartCommand的返回值必须的下面当中的一个常量:
START_NOT_STICKY
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.
START_STICKY
If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), but do not redeliver 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.
START_REDELIVER_INTENT
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.
Stopping a service
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.
说是这个ID是建立在最新的一个请求的,也就是说前面的请求的id和传给onStartCommand方法的ID不一致,只要有新请求,id就变,会不会有开始只有一个执行,然后其他等到这个执行了还没执行,不就stop了,呵呵
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().
Creating a Bound Service
一个绑定服务是一个服务允许应用组件通过调用bindService绑定到他上面创建一个长期存在的关系(通常不允许组件调用startService启动他)。
当我们想和来自程序中的活动或者其他组件的服务交互或者通过进程通信暴露一些应用程序的功能给其他应用,应该创建一个绑定服务。
(1)要创建一个绑定服务,必须实现onBind方法,返回一个定义和服务通信的接口的IBinder(2)其他应用组件然后可以调用bindService(这个方法有个ServiceConnection参数,需要设置一些)方法获得这个接口,开始调用服务上的方法。
要创建一个绑定服务,第一件要做的事就是定义指定客户端如何跟服务通信的接口。(一般我们的是不在服务中创建一个Binder(实现IBinder接口)的实例)。这个接口必须是一个IBinder的实现,同时是服务必须在onBind回调方法返回的。一旦客户端收到这个IBinder,可以通过那个接口和服务交互。
多个客户端可以同时绑定到一个服务。当一个客户端和服务执行完交互,调用unBindService去解绑。一旦没有客户端绑定到服务上,系统销毁这个服务。
有多种方式实现一个绑定服务,而且实现比启动的服务更复杂,所以这个绑定服务在独立的绑定服务文档讨论。
Managing the Lifecycle of a Service
服务的生命周期和活动很像。然而,更重要的是,我们应该更关注我们的服务如何创建和销毁,因为一个服务可以在用户不知道情况下在后台运行。
服务的生命周期重创建到销毁有这两个路劲:
• A started service
另一个组件调用startService()启动这个服务.服务然后在后台无限期运行,必须调用stopSelf停止自己。另一程序也可以调用stopService停止。当服务停止,系统销毁他。
• A bound service
当另一个组件(一个客户端)调用bindService的时候,服务被创建。客户端然后通过IBinder接口和服务通信。多个客户端可以绑定到同一个服务,当他们全部解绑,系统销毁这个服务(服务不需要自己停止)。
这两个路径不是完全分离的。那就是,可以绑定到一个已经由startSercie启动的服务。举例,一个后台音乐服务可以通过调用statService用一个确认要播放的音乐Intent启动。然后,可能当用户想执行一些控制在这个播放器或者得到当前歌曲的信息,一个活动通过调用bindService绑定到服务上。在这样的例子,stopService() or stopSelf() 不能停止服务直到所有的客户端解绑。(所有客户端解绑,应该也不停止服务吧,除非调用这个两个方法)
Implementing the lifecycle callbacks
和活动很像,一个服务有生命周期回调方法我们可以实现去监听服务的状态改变,在适合的实际执行工作。下面的骨架服务展示了每一个生命周期方法。
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
public void onCreate() {
// The service is being created
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The service is starting, due to a call to startService()
return mStartMode;
}
@Override
public IBinder onBind(Intent intent) {
// A client is binding to the service with bindService()
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// All clients have unbound with unbindService()
return mAllowRebind;
}
@Override
public void onRebind(Intent intent) {
// A client is binding to the service with bindService(),
// after onUnbind() has already been called
}
@Override
public void onDestroy() {
// The service is no longer used and is being destroyed
}
}
Note:不像活动的生命周期回来方法,不用调用父类的这些方法的实现。
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().
通过实现写方法,可以监听两个嵌套的服务生命周期循环。
• 服务的整个生命周期发生在onCreate被调用和onDestroy返回之间。项一个活动,服务在onCreate进行初始化设置,在onDestroy中释放所有资源。举例,一个音乐播放服务可以在onCreate中创建音乐播放的线程,然后在onDestroy中停止这个线程。
可以看到,onCreate()和 onDestroy()方法被所有服务调用,无论他们的由startService() 还是bindService()创建。
• 服务的活跃生命时间 从onStartCommand或者onBind开始。每个方法分别处理来自startService或者bindService传递的intent
如果服务是被启动,活跃生命周期随着整个生命周期结束而结束(服务仍然是活跃的,甚至在onStartCommand返回之后)。如果服务是绑定的,活跃生命时间随着onUnbind返回结束。
Note:虽然一个被启动的服务由stopSelf() or stopService()停止, 服务没有一个回调方法(没有onStop回调)。所以,除非服务绑定到一个客户端,否则当服务停止系统销毁他,onDestroy是被接收唯一的回调方法。
上图阐明了服务的典型的回调方法。虽然该图分离了由startService和bindService创建的服务,在心中铭记,任何服务,无论如何启动,可以潜在的允许客户端绑定他。所以,一个最初有onStartCommand方法(通过客户端调用startService)启动的服务,仍然可以接受一个onBind(当一个客户端调用bindService) bind 可以被启动吗,应该是不可以吧。
查看Bound Service更多。
本文详细介绍了Android中的服务组件,包括启动服务和绑定服务的区别及其实现方式。文章讲解了服务的生命周期及其回调方法,并提供了创建服务的具体步骤。

被折叠的 条评论
为什么被折叠?



