Service的生命周期方法比Activity少一些,只有onCreate, onStart, onDestroy
一个Service可以以以下两种形式存在:
· Started(启动) 在一个应用程序以startService() 来启动一个Service时,这个Service将处于“Started”状态。一旦启动,这个Service可以在后台一直运行下去,即使启动它的应用程序已推出。通常,一个处于“started”状态的Service完成某个功能而不会给启动它的应用程序组件返回结果。比如,这个服务(Service)可能是上载或是下载一个文件,当任务完成后,服务自行退出。
· Bound (绑定) 当一个应用程序组件以bindService() 绑定一个Service时,这个Service处于“Bound”状态。处于“Bound”状态的Service提供了一个客户/服务(C/S)调用接口支持其它应用程序组件和它交互,比如发生请求,返回结果,或者使用IPC完成跨进程间通信。一个处于“Bound”的Service只能和与其绑定的应用程序一起运行。多个应用程序组件可以绑定到同一个Service。当所有绑定的应用程序组件都退出绑定后,被“绑定”的Service将被销毁。
对于一个Service来说,它可以是“Started”,“Bound”或者同时处于两种状态。其它任一应用程序组件(比如一个Activity)都可以使用这个Service,即使其它应用程序组件是在不同的应用程序中。当然你可以把Service定义为私有的,这样其它应用程序就无法使用你定义的Service。
要注意的是,一个Service运行在其宿主进程的主线程中--服务不会自己创建新的线程也不运行在独立的进程中(除非你特别指明)。这意味着,如果你的Service需要完成一些很耗CPU资源的操作(比如播放MP3,或者使用网络),你应该在Service中创建新的线程来完成这些工作,从而降低出现程序无响应(ANR)的风险。
Service基础
要创建一个Service,你必须从Service或是其某个子类派生子类。在你的Service子类实现中,你需要重载一些方法以支持Service重要的几个生命周期函数和支持其它应用组件绑定的方法。下面给出几个需要重载的重要方法:
· onStartCommand() Android系统在有其它应用程序组件使用startService()请求启动Service时调用。一旦这个方法被调用,Service处于“Started”状态并可以一直运行下去。如果你实现了这个方法,你需要在Service任务完成时调用stopSelf()或是stopService()来终止服务。如果你只支持“绑定”模式的服务,你可以不实现这个方法。
· onBind() Android系统中有其他应用程序组件使用bindService()来绑定你的服务时调用。在你实现这个方法时,你需要提供一个IBinder接口以支持客户端和服务之间通信。你必须实现这个方法,如果你不打算支持“绑定”,返回Null即可。
· onCreate() Android系统中创建Service实例时调用,一般在这里初始化一些只需单次设置的过程(在onStartCommand和onBind()之前调用),如果你的Service已在运行状态,这个方法不会被调用。
· onDestroy() Android系统中Service不再需要,需要销毁前调用。在你的实现中你需要释放一些诸如线程,注册过的listener,receiver等,这是Service被调用的最后一个方法。
如果一个Service是由startService()启动的(这时 onStartCommand()将被调用),这个Service将一直运行直到调用stopSelf()或其它应用部件调用stopService()为止。
如果一个部件调用bindService()创建一个Service(此时onStartCommand()不会调用),这个Service运行的时间和绑定它的组件一样长。一旦其他组件解除绑定,系统将销毁这个Service。
Android系统只会在系统内存过低且不得不为当前活动的Activity恢复系统资源时才可能强制终止某个Service。如果这个Service绑定到一个活动的Activity,基本上不会被强制清除。如果一个Service被申明成“后台运行”,就几乎没有被销毁的可能。否则的话,如果Service启动后并长期运行,系统将随着时间的增加降低其在后台任务中的优先级,其被杀死的可能性越大。如过你的Service是做为“Started”状态运行,你必须设计后如果在系统重启服务时优雅退出。如果系统杀死你的服务,系统将在系统资源恢复正常时重启你的服务(当然这也取决于onStartCommand()的返回值)。
在Manifest中申明Service
和Activity一样,你必须在Manifest文件中申明应用中使用到的Service。为了声明一个Service,你需要定义<application>的子元素<service>,比如:
1 |
<manifest ...
> |
2 |
... |
3 |
<application ...
> |
4 |
<service android:name=".ExampleService" /> |
5 |
... |
6 |
</application> |
7 |
</manifest> |
<service>还包括一些其它属性,android:name是唯一一个必须定义的属性,它定义了Service的类名。
和Activity一样,你可以为Service定义Intent Filter以支持其它部件隐式调用该服务。如果你只打算在你自己的应用中使用某个Service,那么就不要定义任何Intent Filter。在这种情况下,你必须明确指明Service的类名来启动这个Service。此外,你可以通过设置android:exported属性为false来明确说明该Service为私有,即使你为Service定义了Intent Filter ,其它应用也无法使用你的Service。
创建一个“Started”的Service
当其它应用程序组件使用startService()来启动Service后,这个Service就成为“Started”的Service。这时Service的onStartCommand () 回调函数将会被调用。
当一个Service以startService()启动后,处于“Started”状态,其生命周期独立于启动这个Service的其它应用程序组件,并且可以在后台无限期运行,即使启动它的其它应用程序组件已经退出。在这种情况下,Service可以调用stopSelf()或者其它程序部分调用stopService()来结束这个Service。
一个应用程序组件比如一个Activity可以通过传入Intent使用startService()来启动一个Service,这个Intent指明需要的服务并包含了Service需要的数据。Service在onStartCommand回调函数中可以访问这个Intent。
要注意的是,Service缺省和申明它的应用程序使用同一个进程并且运行在主线程中,因此如果你的Service比较耗时的话,那么这个Service会影响到应用的用户响应性能。为避免这种现象,你应用在Service中创建新线程。
你可以使用下面两个基类来创建一个“Started”的Service。
· Service 这是所有Service的基类,当你派生这个类时,使用新创建的线程来完成Service需要完成的工作非常重要,这是因为Service缺省也会使用你的应用程序的主线程,这可能会影响你应用程序的响应性能。
· IntentService 为Service的一个子类,它会使用一个工作线程来处理所有的请求,每次处理一个请求。这在你无需实现并行处理多个请求时是最好的选择。你只需重载onHandleIntent()方法,这个方法接受每个请求,从而你可以在后台完成所需任务。
派生IntentService类
因为大部分“Started”的Service不需要并行处理多个请求,这时最好的选择是派生自IntentService。
类IntentService可以完成以下工作:
· 创建一个工作线程来处理所有发送到onStartCommand()的请求(Intent),从而和应用的主线程分开。
· 创建一个工作队列来逐个处理每个请求,从而无需考虑多线程编程。
· 在处理完所有请求后中止Service的运行,你无需调用stopSelf()来终止Service。
· 提供onBind()的缺省实现,返回null。
· 提供onStartCommand()的缺省实现,将接受到的Intent发送到工作队列中,然后调用你的onHanleIntent()实现。
因此,对于你来说,只需要提供onHandleIntent()来处理发过来的Intent,当然你可能需要实现Service的一个简单的构造函数。
下例为IntentService的一个简单实现:
01 |
public
class HelloIntentService extends IntentService { |
02 |
03 |
/** |
04 |
*
A constructor is required, and must |
05 |
*
call the super IntentService(String) |
06 |
*
constructor with a name for the worker thread. |
07 |
*/ |
08 |
public
HelloIntentService() { |
09 |
super("HelloIntentService"); |
10 |
} |
11 |
12 |
/** |
13 |
*
The IntentService calls this method from |
14 |
*
the default worker thread with |
15 |
*
the intent that started the service. |
16 |
*
When this method returns, |
17 |
*
IntentService stops the service, as appropriate. |
18 |
*/ |
19 |
@Override |
20 |
protected
void onHandleIntent(Intent intent) { |
21 |
//
Normally we would do some work here, like download a file. |
22 |
//
For our sample, we just sleep for 5 seconds. |
23 |
long
endTime = System.currentTimeMillis() + 5 * 1000; |
24 |
while
(System.currentTimeMillis() < endTime) { |
25 |
synchronized
(this) { |
26 |
try
{ |
27 |
wait(endTime
- System.currentTimeMillis()); |
28 |
}
catch (Exception e) { |
29 |
} |
30 |
} |
31 |
} |
32 |
} |
你需要实现的只是一个构造函数和重载onHandleIntent()。
如果你需要重载其它一些回调函数,比如onCreate(),onStartCommand()或是onDestroy(),注意调用其基类的实现。这样IntentService才能正确管理工作线程的生命周期。
比如重载onStartCommand(),你必须返回基类的onStartCommand()的返回值,这样Intent能够传递到onHandleIntent()的原因:
1 |
@Override |
2 |
public
int onStartCommand(Intent intent, int flags, int startId) { |
3 |
Toast.makeText(this,
"service starting", Toast.LENGTH_SHORT).show(); |
4 |
return
super.onStartCommand(intent,flags,startId); |
5 |
} |
除了onHandleIntent(),此外唯一可以不调用基类实现的回调函数为onBind(),你只要在你需要支持绑定服务时才需要实现该方法。
派生Service类
从上面可以看到使用IntentService可以让实现“Started”的Service变的非常简单,然而如果你需要支持使用多线程并行处理多个请求(而非使用工作队列来依次处理请求),这时你就需要从Service类来派生。
作为比较,下面的例子使用Service实现和上面使用IntentService同样的功能,也是使用一个工作线程来逐个处理每个请求,可以看成是IntentService的一个实现:
01 |
public
class HelloService extends Service { |
02 |
private
Looper mServiceLooper; |
03 |
private
ServiceHandler mServiceHandler; |
04 |
05 |
//
Handler that receives messages from the thread |
06 |
private
final class ServiceHandler extends Handler { |
07 |
public
ServiceHandler(Looper looper) { |
08 |
super(looper); |
09 |
} |
10 |
@Override |
11 |
public
void handleMessage(Message msg) { |
12 |
//
Normally we would do some work here, like download a file. |
13 |
//
For our sample, we just sleep for 5 seconds. |
14 |
long
endTime = System.currentTimeMillis() + 5*1000; |
15 |
while
(System.currentTimeMillis() < endTime) { |
16 |
synchronized
(this) { |
17 |
try
{ |
18 |
wait(endTime
- System.currentTimeMillis()); |
19 |
}
catch (Exception e) { |
20 |
} |
21 |
} |
22 |
} |
23 |
//
Stop the service using the startId, so that we don't stop |
24 |
//
the service in the middle of handling another job |
25 |
stopSelf(msg.arg1); |
26 |
} |
27 |
} |
28 |
29 |
@Override |
30 |
public
void onCreate() { |
31 |
//
Start up the thread running the service. Note that we create a |
32 |
//
separate thread because the service normally runs in the process's |
33 |
//
main thread, which we don't want to block. We also make it |
34 |
//
background priority so CPU-intensive work will not disrupt our UI. |
35 |
HandlerThread
thread = new HandlerThread("ServiceStartArguments", |
36 |
Process.THREAD_PRIORITY_BACKGROUND); |
37 |
thread.start(); |
38 |
|
39 |
//
Get the HandlerThread's Looper and use it for our Handler |
40 |
mServiceLooper
= thread.getLooper(); |
41 |
mServiceHandler
= new ServiceHandler(mServiceLooper); |
42 |
} |
43 |
44 |
@Override |
45 |
public
int onStartCommand(Intent intent, int flags, int startId) { |
46 |
Toast.makeText(this,
"service starting", Toast.LENGTH_SHORT).show(); |
47 |
48 |
//
For each start request, send a message to start a job and deliver the |
49 |
//
start ID so we know which request we're stopping when we finish the job |
50 |
Message
msg = mServiceHandler.obtainMessage(); |
51 |
msg.arg1
= startId; |
52 |
mServiceHandler.sendMessage(msg); |
53 |
|
54 |
//
If we get killed, after returning from here, restart |
55 |
return
START_STICKY; |
56 |
} |
57 |
58 |
@Override |
59 |
public
IBinder onBind(Intent intent) { |
60 |
//
We don't provide binding, so return null |
61 |
return
null; |
62 |
} |
63 |
|
64 |
@Override |
65 |
public
void onDestroy() { |
66 |
Toast.makeText(this,
"service done", Toast.LENGTH_SHORT).show(); |
67 |
} |
68 |
} |
可以看出来,比使用IntentService多了很多工作。然而,由于你自己来处理onStartCommand(),你可以实现并行处理多个请求。当然这不是本例的实现,但是如果你愿意,你可以为每个请求创建一个工作线程来立即处理请求而不使用工作队列。
注意onStartCommand()方法必须返回一个整数,这个返回值定义了如果Android系统在杀死这个Service后又需要使用这个Service后的行为。这个返回值可以有下面几种情况:
· START_NOT_STICKY 如果Android系统在onStartCommand() 返回后杀死了这个Service,系统不会重新创建这个Service,除非它是一个Pending Intent。这是在你的应支持简单的重启没有完成的任务避免无必要的Service运行时ic最好的选项。
· START_STICKY 在Android系统在onStartCommand () 返回后,选择重新创建这个Service并调用Service的onStartCommand () 方法,但不会重新发送上一次的请求。Android系统使用空Intent调用onStartCommand,除非它是一个PendingIntent。这种情况适用于一些媒体播放器服务。
· START_REDELIVER_INTENT在Android系统在onStartCommand() 返回后,选择重新创建这个Service并调用Service的onStartCommand () 方法,并且重新发送上一次的请求。这适用一些比较活跃地进行某些工作的服务,需要立即恢复活动比如下载文件的服务。
启动Service
在Activity或是其他应用程序组件可以通过传递Intent调用startService()方法来启动一个Service。Android系统然后会调用Service的onStartCommand()方法并传入这个Intent对象。
比如,一个Activity可以通过明确指明调用的服务来调用前面创建的HelloService:
1 |
Intent
intent = new Intent(this, HelloService.class); |
2 |
startService(intent); |
startService() 调用后立即返回,Android系统调用Service的onStartCommand(),如果这个Service之前没有运行,系统还将先调用Service的onCreate()方法,然后再调用onStartCommand()。
如果Service没有提供绑定支持,那么使用startService()是唯一可以启动Service的方法。然而,如果你需要Service返回一个结果,那么客户端可以通过创建一个用于广播的延迟Intent(PendingIntent)然后通过Intent发送请求到Service。Service可以利用这个广播(Broadcast)返回结果。
多个启动Service请求将导致多次调用Service的onStartCommand()方法。然而只要一个stopSelf或stopService来停止一个Service的运行。
停止Service
一个“Started”的Service必须管理自己的生命周期,也就是说,除非系统资源不足,Android系统不终止或停止一个Service。因此Service必须调用stopSelf () 方法来终止自身的运行,或者其它部件可以通过stopService () 方法来中止一个Service的运行。
一旦Service被请求终止,系统将尽快销毁这个Service。
但是,如果你的Service需要在onStartCommand()并行处理多个请求,那么你不应再处理完一个请求后就停止Service的运行,因为你可能还会接受到新的请求(在第一个请求处理完就结束则会终止第二个请求的执行)。为避免这种情况,你可以使用带参数的stopSelf(int) 来确保终止Service的请求总是对应于最近的请求。也就是说,在调用stopSelf(int) 时,你通过传入请求的Id (传给onStartCommand 方法的 startId )来终止对应的请求处理。那么如果Service在调用stopSelf (int) 前接受到一个新的请求,那么Id将不会匹配,因此Service也就不会结束。
创建一个支持“绑定”的Service
一个支持“绑定”的Service是指运行其它应用程序之间通过调用bindService() 来绑定到它的Service。支持“绑定”的Service在设计时通常不允许直接使用startService() 来启动它。
在Activity或其它组件需要和一个Service发生交互时,你应该创建一个“绑定”的Service,在这个Service中你可以通过进程间通信接口(IPC)来提供可供其它应用程序组件使用的功能接口。
为了创建一个支持“绑定”的Service,你需要实现onBind() 回调函数并返回一个IBind接口对象,这个对象提供了其它部分可以访问这个Service的服务接口。其它应用程序组件然后可以通过bindService () 方法获得Service的服务接口对象,然后使用这个对象的方法来调用服务。通常“绑定”的Service的运行周期和绑定它的其它应用程序组件的生命周期是一样的。因此如果这个Service不再有应用程序组件与之绑定,Android系统会自动销毁这个Service,而你自己无需停止这个Service。
为了创建一个支持“绑定”的Service所需做的第一件事是定义可供客户端调用的服务接口。这个接口必须为一个IBinder接口,并且你的Service必须通过onBind () 返回这个接口对象。一旦客户端获得这个IBinder接口,就可以通过这个接口对象来使用服务。
多个客户端可以同时绑定到同一个Service,当一个客服端使用好所需的服务后,调用onbindService() 来解除与Service之间的绑定关系。当一个Service没有和它绑定的客户端后,Android系统销毁这个Service。
给用户发送通知
Service通常是在后台运行,它可以通过Toast 通知或是状态条通知来提醒用户发生了某种事件。
一个Toast通知为覆盖在当前屏幕上短时间显示的消息,而状态条通知可以在状态条以图标和文字的方法显示,用户可以选择是否查阅这个通知并作出处理(比如启动一个Activity)。
一般来说,使用状态条通知是在某个后台工作完成后(比如文件下载完毕)通知用户的最好方法。用户可以在扩展后的通知窗口选择某个通知,然后可以点击是否启动一个Activity(比如查看下载好的文件)
在前台运行Service
通常Service在后台运行,但有时某些Service是用户明确知道在运行,即使在系统资源不足时,也不该做为销毁的候选Service,这种Service可以设置成在前台运行,在前台运行的Service必须在状态条显示通知,除非Service停止或者转入后台,这种通知不可以被忽视。
比如,如果一个音乐播放器使用Service来播放,这个Service应该被放在前台运行,因为用户很清楚的知道音乐在播放,而在状态条显示的通知理当显示当前播放的乐曲并且允许用户启动一个Activity来操作这个音乐播放器。
要把一个Service放在前台运行,可以调用startForeground()。这个方法接受两个参数:一个整数来唯一标识一个通知,和显示在状态条上的通知对象。
例如:
要使一个Service推出前台运行,调用stopForeground(). 这个方法接受一个boolean参数,指明是否同时移除状态条上的通知。 这个方法并不会停止Service的运行。但如果你停止一个在前台运行的Service,那么会同时移除状态条的通知。
管理Service的生命周期
和Activity相比,Service的生命周期要简单很多。但你更要关注你的Service是如何创建和销毁的,这是因为Service可以在用户不知道的情况下在后台运行。
Service的生命周期,从其创建后到销毁,可以有两条不同的路径:
“Started”的Service 这个Service是由其它的应用程序组件调用startService()创建的,这个service 可以在后台无限期运行直到调用 stopSelf()或者其它组件调用stopService()来停止它。当Service停止时,系统将销毁这个Service。
支持“绑定”的Service 这种Service是在其它组件调用 bindService()绑定它时创建,客户端然后可以通过服务接口和Serivce通信。客户端可以调用 unbindService () 解除与Service的绑定。多个客户端可以同时绑定同一Service,当一个Service没有客户端和它绑定时,系统则销毁这个Service。
这两条路径并不是完全分开的,也就是说,你可以去绑定一个已经是“Started”状态的Service。比如,一个通过媒体播放的Service可能通过指明需要播放音乐的Intent然后调用startService() 启动的。再往后,用户可能打算来操作媒体播放器,那么一个Activity可以调用 bindServive()来绑定这个Service。在这种情况下,stopSelf()或stopSelf()并不真正停止Service直到所有的客户端都解除与Service的绑定。
实现生命周期回调函数
和Activity类似,Service也提供了一些回调函数接口允许你重载这些方法来监视Service状态的变化并添加合适的处理,下面代码给出一个Service生命周期回调函数实现的框架:
01 |
package
com.example.bookdemo; |
02 |
03 |
import
android.app.Service; |
04 |
import
android.content.Intent; |
05 |
import
android.os.IBinder; |
06 |
07 |
08 |
public
class ExampleService extends Service { |
09 |
//
indicates how to behave if the service is killed |
10 |
int
mStartMode; |
11 |
//
interface for clients that bind |
12 |
IBinder
mBinder; |
13 |
//
indicates whether onRebind should be used |
14 |
boolean
mAllowRebind; |
15 |
16 |
@Override |
17 |
public
void onCreate() { |
18 |
//
The service is being created |
19 |
} |
20 |
@Override |
21 |
public
int onStartCommand(Intent intent, |
22 |
int
flags, int startId) { |
23 |
//
The service is starting, |
24 |
//
due to a call to startService() |
25 |
return
mStartMode; |
26 |
} |
27 |
@Override |
28 |
public
IBinder onBind(Intent intent) { |
29 |
//
A client is binding to the service |
30 |
//
with bindService() |
31 |
return
mBinder; |
32 |
} |
33 |
@Override |
34 |
public
boolean onUnbind(Intent intent) { |
35 |
//
All clients have unbound with unbindService() |
36 |
return
mAllowRebind; |
37 |
} |
38 |
@Override |
39 |
public
void onRebind(Intent intent) { |
40 |
//
A client is binding to the service with bindService(), |
41 |
//
after onUnbind() has already been called |
42 |
} |
43 |
@Override |
44 |
public
void onDestroy() { |
45 |
//
The service is no longer used and is being destroyed |
46 |
} |
47 |
} |
和Activty不同的是,Service的生命周期回调函数没有必要调用基类的对于的方法。
图 1. Servcie的生命周期
通过实现这些回调函数,你可以监视Service生命周期中两个嵌套的循环:
· 整体生命周期 指Service在onCreate()和onDestroy()之间。和Activity类似,Service可以在onCreate () 进行一些初始化工作,而在onDestroy () 中释放资源。比如,一个音乐播放器可以在onCreate() 创建用来播放音乐的线程,而在onDestroy() 停止这个线程。
· 活动生命周期 Service 在 onStartCommand() 或 onBind() 后开始活动,每个方法分别处理来自 startService和 bindService() 发过来请求 Intent。如果是“Started”的Service,那么它活动的生命周期和Service的整个生命周期是一致的。如果是“绑定”的Service,那么它的活动生命周期终止与unbind()。
我们有两种方式启动一个Service,他们对Service生命周期的影响是不一样的。
1 通过startService
Service会经历 onCreate --> onStart
stopService的时候直接onDestroy
如果是 调用者 直接退出而没有调用stopService的话,Service会一直在后台运行。
下次调用者再起来仍然可以stopService。
2 通过bindService
Service只会运行onCreate, 这个时候 调用者和Service绑定在一起
调用者退出了,Srevice就会调用onUnbind-->onDestroyed
所谓绑定在一起就共存亡了。
注意:Service的onCreate的方法只会被调用一次,
就是你无论多少次的startService又 bindService,Service只被创建一次。
如果先是bind了,那么start的时候就直接运行Service的onStart方法,
如果先是start,那么bind的时候就直接运行onBind方法。如果你先bind上了,就stop不掉了,
只能先UnbindService, 再StopService,所以是先start还是先bind行为是有区别的。
Android中的服务和windows中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。
服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。
这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,调用者与服务之间没有关连,
即使调用者退出了,服务仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,
但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。
如果打算采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,
接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,
多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。
如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法.
1.先讲讲怎么使用bindService()绑定服务
应用组件(客户端)可以调用bindService()绑定到一个service.Android系统之后调用service的onBind()方法,它返回一个用来与service交互的IBinder
绑定是异步的.bindService()会立即返回,它不会返回IBinder给客户端.要接收IBinder,客户端必须创建一个ServiceConnection的实例并传
给bindService().ServiceConnection包含一个回调方法,系统调用这个方法来传递要返回的IBinder.
注:只有activities,services,和contentproviders可以绑定到一个service—你不能从一个broadcastreceiver绑定到service.
所以,从你的客户端绑定到一个service,你必须:
-
1实现ServiceConnection.
你的实现必须重写两个回调方法:
-
onServiceConnected()
系统调用这个来传送在service的onBind()中返回的IBinder.
-
OnServiceDisconnected()
Android系统在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了.当客户端解除绑定时,这个方法不会被调用.
-
-
2调用bindService(),传给它ServiceConnection的实现.
-
3当系统调用你的onServiceConnected()方法时,你就可以使用接口定义的方法们开始调用service了.
-
4要与service断开连接,调用unbindService().
当你的客户端被销毁,它将从service解除绑定,但是你必须总是在你完成与service的交互时或当你的activity暂停于是service在不被使用时可以关闭此两种情况下解
除绑定.(下面会讨论更多在适当的时候绑定和解除绑定的问题.
使用这个ServiceConnection,客户端可以绑定到一个service,通过把它传给bindService().例如:
Intentintent = new Intent(this, LocalService.class);
bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
-
第一个bindService()的参数是一个明确指定了要绑定的service的Intent.
-
第二个参数是ServiceConnection对象.
-
第三个参数是一个标志,它表明绑定中的操作.它一般应是BIND_AUTO_CREATE,这样就会在service不存在时创建一个.其它可选的值是BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,不想指定时设为0即可.。
补充事项
下面是一些关于绑定到service的重要事项:
-
你总是需要捕获DeadObjectException异常.它会在连接被打断时抛出.这是被远程方法抛出的唯一异常.
-
对象引用计数是跨进程的作用的.
-
你应该在客户端的生命期内使绑定和解除绑定配对进行,例如:
-
如果你需要在你的activity可见时与service交互,你应该在onStart()绑定并在onStop()中解除绑定.
-
如果你想让你的activity即使在它停止时也能接收回应,那么你可以在onCreate()中绑定并在onDestroy()中解除绑定.注意这意味着你的activity需要使用在自己整
个运行期间使用service(即使位于后台),所以如果service在另一个进程中,那么你增加了这个进程的负担而使它变得更容易被系统杀掉.
注:你一般不应该在你的activity的onResume()和onPause()中绑定和解除绑定到service,因为这些回调方法,出现在每个生命期变化中,并且你需要使发生在这
些变化中的处理最小化.还有,如果你应用中的多个activity绑定到同一个service,并且有一个变化发生在其中两个activity之间,service可能在当前activity解除绑
定(pause中)和下一个绑定前(rusume中)被销毁又重建.
-
2.管理(多个客户端)BoundService的生命期
当一个service的所有客户端都解除绑定,Android系统就销毁它(除非它是从onStartCommand()启动).如果你的service是一个纯boundservice,你不需管理它的生命
期—Android系统会为你管理它.。
然而,如果你选择了实现onStartCommand()回调方法,那么你必须明确地停止service,因为service现在被认为是"开始的".在此情况下,service会一直运行,直
到service使用stopSelf()停止它自己或另外的组件调用了stopService()停止了它,不管是否有客户端绑定了它.
另外,如果你的service已经启动并且接受绑定,那么当系统调用你的onUnbind()方法,你可以选择返回true表示你想在客户端下一次绑定到service时接受一个
对onRebind()的调用(而不是一个对onBind()的调用).onRebind()返回void,但是客户端依然会在它的onServiceConnected()回调中接收到IBinder.下图演示了这种生命其的
逻辑:

3。bindService和startService混合使用时
1.如果先bindService,再startService:
在bind的Activity退出的时候,Service会执行unBind方法而不执行onDestory方法,因为有startService方法调用过,所以Activity与Service解除绑定后会有一个与调用者没有关连的Service存在
2.如果先bindService,再startService,再调用Context.stopService
Service的onDestory方法不会立刻执行,因为有一个与Service绑定的Activity,但是在Activity退出的时候,会执行onDestory,如果要立刻执行stopService,就得先解除绑定
---------------------------
把上面的"如果先bindService,再startService"换成"如果先startService,再bindService",结果是一样的
问题:
如果在一个Activity的onCreate方法中,
先
bindService(serviceIntent, conn, Context.BIND_AUTO_CREATE);
再startService(serviceIntent);
退出这个Activity时,会执行onUnBind
但是再次进入这个Activity的时候,为什么不执行onBind方法了?只有在这个Service销毁后(执行onDestory),再进这个Activity才会执行onBind,还有就是当有两个客户端时,在第一个客户端startServie启动服务再bindService绑定服务,这时跳到第二个客户端里(启动时会调用onBind()),再客户端startServie启动服务再bindService绑定服务,启动时不会调用用onBind()了(因为之前客户端已经启动后没有onDestory()销毁Service,所以再客户端第二次绑定服务时,只会返回IBinder对象给onServiceConnected()),而且要注意的是当,当第一个服务启动并绑定一个服务时,再跳去第二个服务端启动并绑定这个服务时,第二个服务端再解绑时,不会调用onUnbind(),只有回到第一个客户端时,解绑这是才会调用onUnbind(),顺序反过来结果是一样的。得出一个结论是:当一个服务没被onDestory()销毁之前,只有第一个启动它的客户端能调用它的onBind()和onUnbind()。
本文详细介绍了Android Service的两种状态——"启动"和"绑定",以及如何创建和管理这两种Service。重点讲解了Service的生命周期方法,如onCreate、onStartCommand、onBind和onDestroy。此外,还提到了Service在Manifest中的声明、前台运行、通知用户、Service生命周期的管理,以及如何处理多个客户端绑定的情况。最后,文章强调了Service生命周期管理的重要性,包括启动Service和解除绑定Service的影响,以及如何在不同场景下选择合适的方法启动Service。
530

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



