一、Service(服务)概述
-
Service
是Android系统中的四大组件之一。 -
Service
是可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可由其他应用组件启动(如Activity
),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity
)已销毁也不受影响,除非系统必须回收内存资源,否则系统不会停止或销毁Service
。 - 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (
IPC
)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。 -
Service
默认并不会运行在子线程中,Service
是在主线程里执行操作的,因此,不要在Service
中执行耗时的操作,避免因为执行耗时操作而导致ANR,除非你在Service
中创建了子线程来完成耗时操作。
二、两种启动方式
服务基本上分为两种形式:
-
startService
当应用组件(如Activity
)通过调用startService()
启动服务时,服务即处于“start”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,它可能通过网络下载或上传文件。 操作完成后,服务会自行停止运行。 -
bindService
当应用组件通过调用bindService()
绑定到服务时,服务即处于“bind”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
虽然上文是分开概括讨论这两种服务,但是您的服务可以同时以这两种方式运行,也就是说,它既可以是start服务(以无限期运行),也允许bind。问题只是在于您是否实现了一组回调方法:
onStartCommand()
(允许组件启动服务)和onBind()
(允许绑定服务)。
无论应用是处于启动状态还是绑定状态,抑或处于启动并且绑定状态,任何应用组件均可像使用Activity
那样通过调用Intent
来使用服务(即使此服务来自另一应用)。 不过,可以通过AndroidManifest.xml
将服务声明为私有服务,并阻止其他应用访问。
三、生命周期
Service
生命周期。左图显示了使用 startService()
所创建的服务的生命周期,右图显示了使用 bindService()
所创建的服务的生命周期。
四、使用Service的步骤
1.定义一个类继承
Service
(或使用它的一个现有子类如IntentService
)
2.在Manifest.xml
文件中配置该Service
3.使用startService()
或bindService()
方法启动该Service
4.不再使用时,调用stopService()
、stopSelf()
或unbindService()
方法停止该服务
4.1定义一个类继承Service
public class MService extends Service {
/**
* 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。
* 如果服务已在运行,则不会调用此方法。该方法只被调用一次
*/
@Override
public void onCreate() {
super.onCreate();
}
/**
* 每次通过startService()方法启动Service时都会被回调。
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
/**
* 服务销毁时的回调
*/
@Override
public void onDestroy() {
super.onDestroy();
}
/**
* 绑定服务时才会调用 必须要实现的方法
*/
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
虽然这个Service什么都没干,但实际上它是Service组件的框架,如果希望Service组件做某些事情,那么只要在
onCreate()
或onStartCommand()
方法中定义相关业务代码即可
4.2在清单文件声明
定义了上面的Service
之后,接下来需要在Androidmaniferst.xml
文件中配置该Service
,配置Service使用<service../>元素。与配置Activity显示的是,配置Service时也可为<service../>元素配置<intent-filter.../>子元素,用于说明该Service可被那些Intent启动。
<application
...
<service android:name=".MService" >
<intent-filter>
<action android:name="..." />
</intent-filter>
<service/>
</application>
Service包含的属性有
<service android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
. . .
</service>
属性 | 说明 |
---|---|
description | 对服务进行描述,属性值应为对字符串资源的引用,以便进行本地化 |
directBootAware | 设置是否可以在用户解锁设备之前运行,默认值为“false” |
enabled | 设置是否可以由系统来实例化服务。< application >元素有自己的enabled属性,适用于包括服务在内的所有应用程序组件。要启用服务,< application >和< service >属性必须都为“true”(默认情况下都为true)。如果其中一个是“false”,则服务被禁用 |
exported | 设置其他应用程序的组件是否可以调用本服务或与其交互,如果可以,则为“true”。当值为“false”时,只有同一个应用程序或具有相同用户ID的应用程序的组件可以启动该服务或绑定到该服务。该属性的默认值取决于服务是否包含Intent filters。没有任何过滤器意味着它只能通过指定其确切的类名来调用,这意味着该服务仅用于应用程序内部使用(因为其他人不知道类名)。所以在这种情况下,默认值为“false”。 另一方面,如果存在至少一个过滤器,意味着该服务打算供外部使用,因此默认值为“true” |
icon | 服务的图标,属性值应是对drawable资源的引用。如果未设置,则将使用应用程序图标 |
isolatedProcess | 设置该服务是否作为一个单独的进程运行,如果设置为true,此服务将在与系统其余部分隔离的特殊进程下运行,并且没有自己的权限,与它唯一的通信是通过服务API(绑定和启动) |
label | 可以向用户显示的服务的名称,属性值应是对字符串资源的引用 |
name | 服务类的完全限定名 |
permission | 设定组件必须具有的权限,得以启动服务或绑定服务。如果startService(),bindService()或stopService()的调用者没有被授予此权限,则该方法将不会工作,并且Intent对象不会传递到服务中 |
process | 用来运行服务的进程的名称。通常,应用程序的所有组件都运行在应用程序创建的默认进程中,它与应用程序包名具有相同的名称。 < application >元素的process属性可以为所有组件设置不同的默认值,但组件可以使用自己的进程属性覆盖默认值,从而允许跨多个进程扩展应用程序 |
4.3启动和停止Service
通过将 Intent
(指定要启动的服务)传递给 startService()
,从 Activity 或其他应用组件启动服务。Android 系统调用服务的 onStartCommand()
方法,并向其传递 Intent
。
Intent intent = new Intent(this, MService.class);
startService(intent);
- 第一次调用
startService()
方法时,onCreate()
方法、onStartCommand()
方法将依次被调用,而多次调用startService()
时,只有onStartCommand()
方法被调用。 - 启动服务必须管理自己的生命周期。也就是说,除非系统必须回收内存资源,否则系统不会停止或销毁服务,而且服务在
onStartCommand()
返回后会继续运行。因此,服务必须通过调用stopSelf()
自行停止运行,或者由另一个组件通过调用stopService()
来停止它。 - 一旦请求使用
stopSelf()
或stopService()
停止服务,系统就会尽快销毁服务。 - 但是,如果服务同时处理多个
onStartCommand()
请求,则您不应在处理完一个启动请求之后停止服务,因为您可能已经收到了新的启动请求(在第一个请求结束时停止服务会终止第二个请求)。为了避免这一问题,您可以使用stopSelf(int)
确保服务停止请求始终基于最近的启动请求。也就说,在调用stopSelf(int)
时,传递与停止请求的 ID 对应的启动请求的 ID(传递给onStartCommand()
的startId
)。然后,如果在您能够调用stopSelf(int)
之前服务收到了新的启动请求,ID 就不匹配,服务也就不会停止。
注意:为了避免浪费系统资源和消耗电池电量,应用必须在工作完成之后停止其服务。 如有必要,其他组件可以通过调用
stopService()
来停止服务。即使为服务启用了绑定,一旦服务收到对onStartCommand()
的调用,您始终仍须亲自停止服务。
4.4绑定Service并与之通讯
待续。。。
网友评论