Service知识点整理.docx
- 文档编号:5662328
- 上传时间:2022-12-30
- 格式:DOCX
- 页数:14
- 大小:25.55KB
Service知识点整理.docx
《Service知识点整理.docx》由会员分享,可在线阅读,更多相关《Service知识点整理.docx(14页珍藏版)》请在冰豆网上搜索。
Service知识点整理
Service知识点整理
Service简单概述
Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。
服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响。
此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信(IPC)。
例如,服务可以处理网络事物、播放音乐、执行文件I/O或与内容提供程序交互,而这一切均可在后台进行。
Service基本上分为两种形式:
启动
当应用组件(如Activity)通过调用startService()启动服务时,服务即处于“启动”状态。
一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。
已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。
例如,它可能通过网络下载或上传文件。
操作完成后,服务会自动停止运行。
绑定
当应用组件通过调用bindService()绑定到服务时,服务即处于“绑定”状态。
绑定的服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用线程间通信(IPC)跨进程执行这些操作。
仅当与另一个应用组件绑定时,绑定服务才会运行。
多个组件也可以同时绑定到该服务,单全部取消绑定后,该服务即会被销毁。
无论应用处于启动状态还是绑定状态,抑或处于启动并且绑定状态,任何应用组件均可像使用Activity那样通过调用Intent来使用服务(即使此服务来自另外一个应用)。
不过,可以通过清单文件将服务声明为私有服务,并阻止其他应用访问。
基础知识
通过创建Service子类(或使用它的一个现有子类)来创建服务。
在现实中,需要重写一些回调方法,已处理服务生命周期的某些关键方面并提供一种机制将组件绑定到服务。
onStartCommand()
当另一个组件(如Activity)通过调用startService()请求启动服务时,系统将调用此方法。
一旦执行此方法,服务即会启动并可在后台无限期运行。
在服务工作完成后,需要通过调用stopSelf()或stopService()来停止服务。
(如果只提供绑定服务,则无需实现此方法)。
onBind()
当另一个组件香通过调用bindService()与服务绑定(例如执行RPC)时,系统将调用此方法。
在此方法的现实中,您必须通过返回IBinder提供一个接口,提供客户端用来与服务进行通信。
请务必实现此方法,但如果并不希望允许绑定,则应返回null。
onCreate()
首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用onStartCommand()或onBind()之前)。
如果服务已经在运行,则不会调用此方法。
onDestroy()
当服务不在使用且当被销毁时,系统将调用此方法。
服务应该实现此方法来清理所有资源,如线程、注册的监听器、接收器等。
这是服务接收的最后一个调用。
使用清单文件声明服务
如同Activity(以及其他组件)一样,必须在应用的清单文件中声明所有服务。
要声明服务,请添加元素作为元素的子元素。
例如:
...
name=".ExampleService" android: enabled=["true"|"false"] android: exported=["true"|"false"] android: isolatedProcess=["true"|"false"] android: icon="drawableresource" android: lable="stringresource" android: name="string" android: permission="string" android: process="string"> ... exported: 代表是否能被其他应用隐式调用,其默认值时由service中有无intent-filter决定的,如果有,默认值为true,否则为false。 为false的情况下,即使有intent-filter匹配,也无法打开,即无法被其他应用隐式调用。 name: 对应Service类名 permission: 是权限声明 process: 是否需要单独在进程中运行,当设置为Android: process=”: remote”时,代表Service在单独的进程中运行。 注意“: ”很重要,它的意思是只要在当前进程名称前附加上当前的包名,所以“remote”和”: remote”不是一个意思,前者的进程名称为: remote,而后者的进程名称为: App-pakageName: remote。 isolatedProcess: 设置true意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。 与其通信的唯一途径是通过服务的API(bindandstart)。 enabled: 是否可以被系统实例化,默认为true因为父标签已有enable属性,所以必须两个都为默认值true的情况下才会被激活,否则不会激活。 启动服务 Intentintent=newIntent(this,TestService.class); startService(intent); onStartCommand(Intentintent,intflag,intstartId) intent: 启动时,启动组件传递过来的Intent,如Activity可利用Intent封装所需要的参数并传递给Service flags: 表示启动请求时是否有额外数据,可选值有0,START_FLAG_REDELIVERY,START_FLAG_RETRY,0代表没有。 START_FLAG_REDELIVERY 这个值代表了onStartCommand方法的返回值为 START_REDELIVER_INTENT,而且在上一次服务被杀死前会去调用stopSelf方法停止服务。 其中START_REDELIVER_INTENT意味着当Service因内存不足而被系统kill后,则会重建服务,并通过传递给服务的最后一个Intent调用onStartCommand(),此时Intent时有值的。 START_FLAG_RETRY 该flag代表当onStartCommand调用后一直没有返回值时,会尝试重新去调用onStartCommand()。 startId: 指明当前服务的唯一ID,与stopSelfResult(intstartId)配合使用,stopSelfResult可以更安全地根据ID停止服务。 实际上onStartCommand的返回值int类型才是最最值得注意的,它有三种可选值,START_STICKY,START_NOT_STICKY,START_REDELIVER_INTENT,它们具体含义如下: START_STICKY 当Service因内存不足而被系统kill后,一段时间后内存再次空闲时,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand方法,但其中的Intent将是null,除非有挂起的Intent,如pendingintent,这个状态下比较适用于不执行命令、但无限期运行并等待作业的媒体播放器或类似服务。 START_NOT_STICKY 当Service因内存不足而被系统kill后,即使系统内存再次空闲时,系统也不会尝试重新创建此Service。 除非程序中再次调用startService启动此Service,这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。 START_REDELIVER_INTENT 当Service因内存不足而被系统kill后,则会重建服务,并通过传递给服务的最后一个Intent调用onStartCommand(),任何挂起Intent均依次传递。 与START_STICKY不同的是,其中的传递的Intent将是非空,是最后一次调用startService中的intent。 这个值适用于主动执行应该立即恢复的作业(例如下载文件)的服务。 由于每次启动服务(调用startService)时,onStartCommand方法都会被调用,因此我们可以通过该方法使用Intent给Service传递所需要的参数,然后在onStartCommand方法中处理的事件,最后根据需求选择不同的Flag返回值,以达到对程序更友好的控制。 Service绑定服务 绑定服务是Service类的实现,可让其他应用与其绑定和交互。 要提供服务绑定,您必须实现onBind()回调方法。 该方法返回的IBinder对象定义了客户端用来与服务进行交互的编程接口。 绑定到已启动服务 正如服务文档中所述,您可以创建同时具有已启动和绑定两种状态的服务。 也就是说,可通过调用startService()启动该服务,让服务无限期运行;此外,还可通过调用bindService()使客户端绑定到服务。 如果您确实允许服务同时具有已启动和绑定状态,则服务启动后,系统“不会”在所有客户端都取消绑定时销毁服务。 为此,您必须通过调用stopSelf()或stopService()显式停止服务。 尽管您通常应该实现onBind()或onStartCommand(),但有时需要同时实现这两者。 例如,音乐播放器可能发现让其服务无限期运行并同时提供绑定很有用处。 这样一来,Activity便可启动服务进行音乐播放,即使用户离开应用,音乐播放也不会停止。 然后,当用户返回应用时,Activity可绑定到服务,重新获得回放控制权。 请务必阅读管理绑定服务的生命周期部分,详细了解有关为已启动服务添加绑定时该服务的生命周期信息。 客户端可通过调用bindService()绑定到服务。 调用时,它必须提供ServiceConnection的实现,后者会监控与服务的连接。 bindService()方法会立即无值返回,但当Android系统创建客户端与服务之间的连接时,会对ServiceConnection调用onServiceConnected(),向客户端传递用来与服务通信的IBinder。 多个客户端可同时连接到一个服务。 不过,只有在第一个客户端绑定时,系统才会调用服务的onBind()方法来检索IBinder。 系统随后无需再次调用onBind(),便可将同一IBinder传递至任何其他绑定的客户端。 当最后一个客户端取消与服务的绑定时,系统会将服务销毁(除非startService()也启动了该服务)。 实际上我们必须提供一个IBinder接口的实现类,该类用以提供客户端用来与服务进行交互的编程接口,该接口可以通过三种方法定义接口: 扩展Binder类 如果服务是提供给自有应用专用的,并且Service(服务端)与客户端相同的进程中运行(常见情况),则应通过扩展Binder类并从onBind()返回它的一个实例来创建接口。 客户端收到Binder后,可利用它直接访问Binder实现中以及Service中可用的公共方法。 如果我们的服务只是自有应用的后台工作线程,则优先采用这种方法。 不采用该方式创建接口的唯一原因是,服务被其他应用或不同的进程调用。 使用Messenger Messenger可以翻译为信使,通过它可以在不同的进程中共传递Message对象(Handler中的Messager,因此Handler是Messenger的基础),在Message中可以存放我们需要传递的数据,然后在进程间传递。 如果需要让接口跨不同的进程工作,则可使用Messenger为服务创建接口,客户端就可利用Message对象向服务发送命令。 同时客户端也可定义自有Messenger,以便服务回传消息。 这是执行进程间通信(IPC)的最简单方法,因为Messenger会在单一线程中创建包含所有请求的队列,也就是说Messenger是以串行的方式处理客户端发来的消息,这样我们就不必对服务进行线程安全设计了。 使用AIDL AIDL(Android接口定义语言)执行所有将对象分解成原语的工作,操作系统可以识别这些原语并将它们编组到各进程中,以执行IPC。 之前采用Messenger的方法实际上是以AIDL作为其底层结构。 如上所述,Messenger会在单一线程中创建包含所有客户端请求的队列,以便服务一次接收一个请求。 不过,如果您想让服务同时处理多个请求,则可直接使用AIDL。 在此情况下,您的服务必须具备多线程处理能力,并采用线程安全式设计。 如需直接使用AIDL,您必须创建一个定义编程接口的.aidl文件。 AndroidSDK工具利用该文件生成一个实现接口并处理IPC的抽象类,您随后可在服务内对其进行扩展。 扩展Binder类 前面描述过,如果我们的服务仅供本地应用使用,不需要跨进程工作,则可以实现自有Binder类,让客户端通过该类直接访问服务中的公共方法。 其使用开发步骤如下 1,创建BindService服务端,继承自Service并在类中,创建一个实现IBinder接口的实例对象并提供公共方法给客户端调用 2,从onBind()回调方法返回此Binder实例。 3,在客户端中,从onServiceConnected()回调方法接收Binder,并使用提供的方法调用绑定服务。 注意: 此方式只有在客户端和服务位于同一应用和进程内才有效,如对于需要将Activity绑定到在后台播放音乐的自有服务的音乐应用,此方式非常有效。 另一点之所以要求服务和客户端必须在同一应用内,是为了便于客户端转换返回的对象和正确调用其API。 服务和客户端还必须在同一进程内,因为此方式不执行任何跨进程编组。 扩展Binder类实现的Service端 privateLocalBinderbinder=newLocalBinder(); /** *创建Binder对象,返回给客户端即Activity使用,提供数据交换接口 */ publicclassLocalBinderextendsBinder{ //声明当前对象this returnLocalService.this; } /** *把Binder类返回给客户端 */ @Nullable @Override publicIBinderonBind(Intentintent){ returnbinder; } 扩展Binder类客户端实现 /** *ServiceConnection代表与服务的链接,它只有两个方法, *onServiceConnected和onServiceDisconnected, *前者是在操作者的链接一个服务成功时被调用,而后者是在服务崩溃或者被杀死导致的连接中断时被调用 */ privateServiceConnectionconn; privateLocalServicemService; conn=newServiceConnection(){ @Override publicvoidonServiceConnected(ComponentNamename,IBinderbinder){ //获取Binder LocalService.LocalBinderbinder=(LocalService.LocalBinder)binder; mService=binder.getService(); } @Override publicvoidonServiceDisconnected(ComponentNamename){ mService=null; } } //开启绑定 Intentintent=newIntent(this,LocalService.class); bindService(intent,conn,Service.BIND_AUTO_CREATE); 使用Messenger 如需让服务与远程进程通信,则可使用Messenger为您的服务提供接口。 利用此方法,您无需使用AIDL便可执行进程间通信(IPC)。 以下是Messenger的使用方法摘要: 服务实现一个Handler,由其接收来自客户端的每个调用的回调 Handler用于创建Messenger对象(对Handler的引用) Messenger创建一个IBinder,服务通过onBind()使其返回客户端 客户端使用IBinder将Messenger(引用服务的Handler)实例化,然后使用后者将Message对象发送给服务 服务在其Handler中(具体地讲,是在handleMessage()方法中)接收每个Message。 这样,客户端并没有调用服务的“方法”。 而客户端传递的“消息”(Messenger对象)是服务在其Handler中接收的。 /**Commandtotheservicetodisplayamessage*/ staticfinalintMSG_SAY_HELLO=1; /** *Handlerofincomingmessagesfromclients. */ classIncomingHandlerextendsHandler{ @Override publicvoidhandleMessage(Messagemsg){ switch(msg.what){ caseMSG_SAY_HELLO: Toast.makeText(getApplicationContext(),"hello! ",Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** *TargetwepublishforclientstosendmessagestoIncomingHandler. */ finalMessengermMessenger=newMessenger(newIncomingHandler()); /** *Whenbindingtotheservice,wereturnaninterfacetoourmessenger *forsendingmessagestotheservice. */ @Override publicIBinderonBind(Intentintent){ Toast.makeText(getApplicationContext(),"binding",Toast.LENGTH_SHORT).show(); returnmMessenger.getBinder(); } 请注意,服务就是在Handler的handleMessage()方法中接收传入的Message,并根据what成员决定下一步操作。 客户端只需根据服务返回的IBinder创建一个Messenger,然后利用send()发送一条消息。 例如,以下就是一个绑定到服务并向服务传递MSG_SAY_HELLO消息的简单Activity: /**Messengerforcommunicatingwiththeservice.*/ MessengermService=null; /**Flagindicatingwhetherwehavecalledbindontheservice.*/ booleanmBound; /** *Classforinteractingwiththemaininterfaceoftheservice. */ privateServiceConnectionmConnection=newServiceConnection(){ publicvoidonServiceConnected(ComponentNameclassName,IBinderservice){ //Thisiscalledwhentheconnectionwiththeservicehasbeen //established,givingustheobjectwecanuseto //interactwiththeservice.Wearecommunicatingwiththe //serviceusingaMessenger,soherewegetaclient-side //representationofthatfromtherawIBinderobject. mService=newMessenger(service); mBound=true; } publicvoidonServiceDisconnected(ComponentNameclassName){ //Thisiscalledwhentheconnectionwiththeservicehasbeen //unexpectedlydisconnected--thatis,itsprocesscrashed. mService=null; mBound=false; } }; publicvoidsayHello(Viewv){ if(! mBound)return; //Createandsendamessagetotheservice,usingasupported'what'value Messagemsg=Message.obtain(null,MessengerService.MSG_SAY_HELLO,0,0); try{ mService.send(msg); }catch(RemoteExceptione){ e.printStackTrace(); } } 此示例并未说明服务如何对客户端作出响应。 如果您想让服务作出响应,则还需要在客户端中创建一个Messenger。 然后,当客户端收到onServiceConnected()回调时,会向服务发送一条Message,并在其send()方法的replyTo参数中包含客户端的Messenger。 Messenger方式进行进程间通信的原理图: Messenger进程
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Service 知识点 整理