四大组件之二 -- Service

此章节参考Android官网内容而编写,如有遗漏,后面会慢慢补上。

一、Service是什么。

Service是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。
例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。

服务分为两种形式:

启动:当应用组件(如 Activity)通过调用startService()启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,它可能通过网络下载或上传文件。 操作完成后,服务会自行停止运行。

绑定:当应用组件通过调用bindService()绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

您的服务可以同时以这两种方式运行,也就是说,它既可以是启动服务(以无限期运行),也允许绑定。问题只是在于您是否实现了一组回调方法:onStartCommand()(允许组件启动服务)和onBind()(允许绑定服务)。

二、创建Service。

要创建服务,您必须创建Service的子类(或使用它的一个现有子类)。在实现中,您需要重写一些回调方法,以处理服务生命周期的某些关键方面并提供一种机制将组件绑定到服务(如适用)。 应重写的最重要的回调方法包括:

onStartCommand():当另一个组件(如 Activity)通过调用startService()请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果您实现此方法,则在服务工作完成后,需要由您通过调用stopSelf()或stopService()来停止服务。(如果您只想提供绑定,则无需实现此方法。)

onBind():当另一个组件想通过调用bindService()与服务绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,您必须通过返回IBinder提供一个接口,供客户端用来与服务进行通信。请务必实现此方法,但如果您并不希望允许绑定,则应返回 null。

onCreate():首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用onStartCommand()或onBind()之前)。如果服务已在运行,则不会调用此方法。

onDestory():当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用。

如果组件通过调用startService()启动服务(这会导致对onStartCommand()的调用),则服务将一直运行,直到服务使用stopSelf()自行停止运行,或由其他组件通过调用stopService()停止它为止。

如果组件是通过调用bindService()来创建服务(且调用onStartcommand(),则服务只会在该组件与其绑定时运行。一旦该服务与所有客户端之间的绑定全部取消,系统便会销毁它。

使用清单文件声明服务:

要声明服务,请添加<service>元素作为<application>元素的子元素。

<service      description="string resource"
android:directBootAware=["true"|"false"]
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>

android:name属性是唯一必需的属性,用于指定服务的类名。应用一旦发布,即不应更改此类名,如若不然,可能会存在因依赖显式 Intent 启动或绑定服务而破坏代码的风险.

为了确保应用的安全性,请始终使用显式 Intent 启动或绑定Service,且不要为服务声明 Intent 过滤器。

启动服务:

启动服务由另一个组件通过调用startService()启动,这会导致调用服务的onStartCommand()方法。

服务启动之后,其生命周期即独立于启动它的组件,并且可以在后台无限期地运行,即使启动服务的组件已被销毁也不受影响。 因此,服务应通过调用stopSelf()结束工作来自行停止运行,或者由另一个组件通过调用stopService()来停止它。

应用组件(如 Activity)可以通过调用startService()方法并传递Intent对象(指定服务并包含待使用服务的所有数据)来启动服务。服务通过onStartCommand()方法接收此Intent

例如,假设某 Activity 需要将一些数据保存到在线数据库中。该 Activity 可以启动一个协同服务,并通过向startService()传递一个 Intent,为该服务提供要保存的数据。服务通过onStartCommand()接收 Intent,连接到互联网并执行数据库事务。事务完成之后,服务会自行停止运行并随即被销毁。

您可以扩展两个类来创建启动服务:

Service 

这是适用于所有服务的基类。扩展此类时,必须创建一个用于执行所有服务工作的新线程,因为默认情况下,服务将使用应用的主线程,这会降低应用正在运行的所有 Activity 的性能。

IntentService

这是Service的子类,它使用工作线程逐一处理所有启动请求。如果您不要求服务同时处理多个请求,这是最好的选择。 您只需实现onHandleIntent()方法即可,该方法会接收每个启动请求的 Intent,使您能够执行后台工作。

例如,Activity 可以结合使用显式 Intent 与startService(),启动上文中的示例服务 (HelloService):

Intentintent=newIntent(this,HelloService.class);

startService(intent);

startService()方法将立即返回,且 Android 系统调用服务的onStartCommand()方法。如果服务尚未运行,则系统会先调用onCreate(),然后再调用onStartCommand()

如果服务亦未提供绑定,则使用startService()传递的 Intent 是应用组件与服务之间唯一的通信模式。但是,如果您希望服务返回结果,则启动服务的客户端可以为广播创建一个PendingIntent(使用getBroadcast()),并通过启动服务的Intent传递给服务。然后,服务就可以使用广播传递结果。

多个服务启动请求会导致多次对服务的onStartCommand()进行相应的调用。但是,要停止服务,只需一个服务停止请求(使用stopSelf()stopService())即可。

停止服务:

启动服务必须管理自己的生命周期。也就是说,除非系统必须回收内存资源,否则系统不会停止或销毁服务,而且服务在onStartCommand()返回后会继续运行。因此,服务必须通过调用stopSelf()自行停止运行,或者由另一个组件通过调用stopService()来停止它。

一旦请求使用stopSelf()stopService()停止服务,系统就会尽快销毁服务。

但是,如果服务同时处理多个onStartCommand()请求,则您不应在处理完一个启动请求之后停止服务,因为您可能已经收到了新的启动请求(在第一个请求结束时停止服务会终止第二个请求)。为了避免这一问题,您可以使用stopSelf(int)确保服务停止请求始终基于最近的启动请求。也就说,在调用stopSelf(int)时,传递与停止请求的 ID 对应的启动请求的 ID(传递给onStartCommand()的startId)。然后,如果在您能够调用stopSelf(int)之前服务收到了新的启动请求,ID 就不匹配,服务也就不会停止。

创建绑定服务:

绑定服务允许应用组件通过调用bindService()与其绑定,以便创建长期连接(通常不允许组件通过调用startService()启动它)。

如需与 Activity 和其他应用组件中的服务进行交互,或者需要通过进程间通信 (IPC) 向其他应用公开某些应用功能,则应创建绑定服务。

要创建绑定服务,必须实现onBind()回调方法以返回IBinder,用于定义与服务通信的接口。然后,其他应用组件可以调用bindService()来检索该接口,并开始对服务调用方法。服务只用于与其绑定的应用组件,因此如果没有组件绑定到服务,则系统会销毁服务(您不必按通过onStartCommand()启动的服务那样来停止绑定服务)。

要创建绑定服务,首先必须定义指定客户端如何与服务通信的接口。 服务与客户端之间的这个接口必须是IBinder的实现,并且服务必须从onBind()回调方法返回它。一旦客户端收到IBinder,即可开始通过该接口与服务进行交互。

多个客户端可以同时绑定到服务。客户端完成与服务的交互后,会调用unbindService()取消绑定。一旦没有客户端绑定到该服务,系统就会销毁它。

实现生命周期回调


左图显示了使用startService()所创建的服务的生命周期,右图显示了使用bindService()所创建的服务的生命周期。

通过实现这些方法,您可以监控服务生命周期的两个嵌套循环:

整个生命周期:服务的整个生命周期从调用onCreate()开始起,到onDestroy()返回时结束。与 Activity 类似,服务也在onCreate()中完成初始设置,并在onDestroy()中释放所有剩余资源。例如,音乐播放服务可以在onCreate()中创建用于播放音乐的线程,然后在onDestroy()中停止该线程。
无论服务是通过startService()还是bindService()创建,都会为所有服务调用onCreate()onDestroy()方法。

有效生命周期:服务的有效生命周期从调用onStartCommand()onBind()方法开始。每种方法均有 {Intent对象,该对象分别传递到startService()bindService()
对于启动服务,有效生命周期与整个生命周期同时结束(即便是在onStartCommand()返回之后,服务仍然处于活动状态)。对于绑定服务,有效生命周期在onUnbind()返回时结束。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • [文章内容来自Developers] Service是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。...
    岳小川阅读 830评论 0 7
  • 服务基本上分为两种形式 启动 当应用组件(如 Activity)通过调用 startService() 启动服务时...
    pifoo阅读 1,202评论 0 8
  • 前言:本文所写的是博主的个人见解,如有错误或者不恰当之处,欢迎私信博主,加以改正!原文链接,demo链接 Serv...
    PassersHowe阅读 1,335评论 0 5
  • 一段时间不用,知识点就会忘,所以整理下一些基本的知识点,加深下印象,便于以后复习。这篇说一下Android中四大组...
    朋永阅读 429评论 0 2
  • 蜜 夜 夜深沉,虫鸣不绝耳 幽谧,深邃,淡而远 窗前,月光编织成的 白色帽子飘落至石阶 透出优雅绝伦的质感 拣...
    瑞意隽永阅读 724评论 7 18