Service

本文详细介绍了Android中的服务概念,包括服务的两种形式:启动服务和绑定服务。解释了如何创建这两种服务,以及它们如何与应用程序组件交互。此外,还讨论了服务的生命周期管理、前台服务的运行、与用户的通知交互等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个service是一个应用的组件可以长时间在后台运行并且不提供用户接口。其他应用组件可以启动一个服务并且它可以运行在后台即使用户更替大另外一个应用。此外,一个组件绑定一个service来与之交互,通过进程间的通讯(ipc)。比如,一个服务执行网络任务,播放音乐,执行文件的输入输出,或者和一个内容提供者进行交互,所有的都在后台。

一个service可以从本质上分为2种形式。

         启动:

一个service被启动当一个应用的组件(比如一个activity)启动它可以调用startService(),一旦启动service可以无期限的运行在后台,即使组件启动它后被销毁。通常启动一个服务执行一单个操作并且不返回结果。比如下载,上传一个文件。当操作结束后,服务停止自己。

 

         范围:

一个服务被限制当一个应用的组件调用bindService()绑定他,一个限制的服务提供了服务接口允许组件和服务进行交互,发送请求,获取结果等等通过进程之间的通信。一个限制的服务运行和组件一样。多个组件绑定服务时,当所有的解绑后service被销毁。

 

不管是否你的应用是否启动,界限或者两者都是,任何一个应用组件可以使用服务(即使是单独的应用),在同一个方式里任何的组件可以使用一个activity通过启动一个意图。但是,你需要声明为私有服务,在清单文件中,并且屏蔽其他的应用。这个讨论更多在描述服务清单部分。

注意:一个服务运行在一个主线程中,服务不创建自己的线程和不要运行一个单独的进程。这种意思是,假如你的服务需要cpu做密集的服务,你可以重新创建一个新的线程为这个服务让他工作。用单独的线程,你可以减少应用anr错误的危险,应用的主线程专门用来交互。

基础

创建一个service,你必须继承Service类,在你的实现时,你需要覆盖一下回调的方法来处理生命周期并且提供一个途径为绑定一个服务,在适当的时候。这些是最重要的回调方法需要覆盖。

onStartCommad():系统调用方法当另外一个组件比如Activity请求一个服务被启动时调用startService().当这个方法执行,服务被启动并可以无限期的运行在后台。假如你实现了它,你有义务停止工作,当你调用stopSelf()或stopService()。(假如你只是想提供绑定,你不需要实现这个方法)

onBind():这个系统调用这个方法当另外一个组件想绑定服务(比如执行RPC),被执行bindService().在你实现这个方法,你必须提供一个接口可以让客户和服务进行交流,返回一个IBinder。你必须实现这个方法,但是假如你不想绑定你可以返回null。

onCreate():系统调用这个方法当服务第一次被创建,这个被执行一次(在onstartcommand()和onBind()之前)。假如服务已经在运行,这个方法就不会被调用。

onDestory():这个是系统调用方法,当服务不再被使用并将被销毁。你的服务必须实现他清除任何的资源,比如线程,注册的监听,接收器等等。这个方法是最后调用的。

 

假如一个组件调用服务用startService(),然后服务就一直运行直到它停止或另外一个组件停止它调用stopSerivce()。

 

假如一个主机调用bindSrvice()创建一个服务,然后这个服务运行和组件生命周期一样长。一旦服务从所有的客户端里被解绑,系统直接销毁它。

Android系统将强制停止服务当内存低时并且必须恢复系统资源为用户聚焦的activity。假如服务被限制在一个用户聚焦的activity。然后它就不容易被杀死,假如服务被宣布是运行在前台的,它将几乎不会被杀死。否则,假如服务被启动并且运行了很长时间,然后系统将会降低他的后台任务级别服务将很容易被杀死,如果你的服务被开启,你必须设计一个更好的方式处理由系统重新启动。假如系统杀死了你的服务,它将被重新启动,然后你必须使你的资源尽快的生效(这个可以通过一个返回值onStartCommand),更多的信息关于系统销毁一个服务看Processes and Threading

在接下来部分,我将会看到你这样创建各种服务并且这样使用各个应用组件。

 

描述服务在清单文件中

像activity一样,你必须声明所有的服务在你的应用清单文件中。

这里有其他的属性包含在<service>标签定义了属性文件想权限服务和运行在哪个进程中。比如与android:name属性是必须的属性,它指定了服务类的名字。一旦一发布你的应用,不要修改他的名字,因为假如你做了你也许会打破一些显示意图的引用你的服务。

看<service>属性元素引用更多的信息描述你的服务在清单列文件中。

仅仅看一个activity,一个服务被定义一个过滤器允许另外的组件调用隐式的意图。被声明的意图过滤器,组件在应用安装到你的设备中可能启动你的服务,假如声明了一个过滤器适合一个意图另一个应用启动startService()。

假如你计划你的服务只在本地(另外的应用不能使用),然后你不必支持过滤器。在没有任何过滤器,你必须启动一个服务用意图显示的类的名字。更多的信息关于启动一耳光服务在接下来会被讨论。

另外,你必须确认你的服务是私有的对你的应用假如你包含了一个android:exported属性并设置它为false。这个很有效及时你提供意图过滤器。

 

创建一个启动服务

一个被开始的服务被组件调用startService(),结果是调用service的onstartCommand()方法。当一个服务被启动,他的生命周期独立于一个启动它的组件并且服务可以无限期的运行,即使组件被销毁。像这样,这个服务应该停止当工作做完后调用stopSelf()。或者另一个组件调用stopService()。

         一个应用组件像一个activity可以启动一个服务当调用startService并且通过Intent指定服务和包含是需要被服务用的数据。这个服务接收这个Intent在onStartCommand()方法。

         举个例子,假设一个activity需要保存一些在线的数据。Activity可以启动一个组件服务并传递给它数据保存通过用意图通过startService()。这个服务接收到意图在onStartCommand(),连接到互联网并且执行数据库操作。当操作做完后服务停止并销毁。

注意:一个服务运行在同一个进程中在一个被声明的应用中,在应用的主线程中默认的。所以你的服务执行密集型或者阻塞型操作当同一个应用中交互,服务将会减慢activity的执行。为了避免影响应用执行,你必须启动一个新的线程内部服务。

传统的,这有两个雷可以可以继承创建一个启动服务。

 

Service:这个是所有的Service的基类。当你继承这个类,它非常重要你创建一个新的线程对所有的服务工作,因为服务用你应用主线程,默认的,这个会是activity执行变的慢。

IntentService:这个是Service的子类用来一个工作线程来执行所有的请求。这个是一个号的操作方式加入你不想你的服务通过执行多个请求。所有你需要的执行的是实现onHandleIntent().这个是接收意图为每一个启动的请求你可以在后台工作。

接下来部分描述了你可以怎样实现你的服务使用这些类。

 

实现IntentService类

         因为许多开启的服务不需要同时执行多个请求(这里可能是一个多线程危险的地方),这样可能更好假如你继承使用你IntentService类。

         IntentService接下来做的:

1.      创建一个默认的工作线程执行所有的意图启动一个onStartCommand()独立于你应用的主线程。

2.      创建一个工作队列通过一个意图执行onHandleInten()实现,你不用担心多线程的问题。

3.      停止服务在所有的请求被执行后,你不用调用stopSelf().

4.      提供默认的继承方法onBind()返回一个null。

5.      提供一个默认的onStartCommand()发送你的工作队列,然后给onHandleIntent()实现。

 

所有增加的所有你可以做的在onHandleIntent()用来工作,提供给客户端。

 

这个所需要的是一个构造函数和onHandIntent()实现。

假如你希望覆盖启动的回调函数,比如onCreate(),onStartCommand(),或onDestroy(),需要确认调用超类的实现。以至于IntentService可以处理工作线程的生命周周期。

         除了onHandleIntent(),只有onBind()方法不用调用它的超类(但是你需要实现他当你的服务被绑定)

在下一部分,你可以看同一的服务继承实现当你继承基类Service类,这个需要更多的代码但是可以提供你当你需要执并发请求时。

 

继承service类

在你前面看到的部分,用IntentService使你实现简单的服务。假如,你请求服务执行多线程(而不是启动请求通过一个工作队列),然后你可以继承Service类执行每一个意图。相比之下,接下来的例子代码实现了Service类来执行相同的工作和IntentService一样。这也是,每一个开始请求,它使用一个工作线程来执行工作并且工作只有一个请求。

 

看起来,它做了很多工作比用IntentService。

 

然而,因为你执行每次都调用onStartCommand(),你可以执行并非请求。这个例子没有做,但是如果你想的话可以创建一个新的线程为每个请求并且立刻运行他们(而不是等待前一个请求完成)。

注意onStartCommand()方法必须返回一个整数。这个整数值描述了当系统需要继续这个额服务,这个服务已经被杀掉。(这个在上面讨论过,默认继承IntentService已经执行,虽然你可以修改它),这个返回值从onStartCommand()一定是下面的常数。

START_NOT_STICKY:假如系统杀死了服务在onStartCommand()返回后,不在从新创建这个服务,除非这里发送意图。这个是非常安全的操作避免你的服务当不是必须的时候,并且当你的应用可以的启动任务未完成的工作。

         START_STICKY:假如系统杀死服务在onStartCommand返回后,从新创建服务并调用onStartCommand,但是不从新发送最后的意图。相反的,系统调用onStartCommand()在没有意图,除非从新启动一个挂起的意图开启服务,在这种情况下,这里的意图被传送。这个适合媒体播放器(或者类似的服务)不用执行命令,但是运行下去或等待工作。

         START_REDELIVER_INTENT:假如系统杀死服务在onStartCommand返回之后,重新创建服务并调用onStartCommand带上最后的被发送的意图。任何的挂起意图依次传递。这个是适合服务activity执行一个工作必须马上恢复,比如下载服务。

更多的返回值看相关的文档。

 

开始一个服务

你可以开始一个服务从一个activity或者另外的一些应用的组件中被Intent(指定服务启动)startService().这个android系统会调用服务的onStartCommand()方法。并且传递一个意图(你不能直接启动onStartCommand())。

比如,一个activity可以启动一个服务在前面的服务中带一个明确的意图用startService();

         startService()方法可以马上返回并系统调用服务的onStartCommand()方法。假如服务没有在运行,系统会先调用onCreate(),然后调用onStartCommand()。

         假如服务没有提供绑定,用startService传递意图是唯一的方式在应用的组件和服务交流。但是假如你想服务发送一个返回数据,客户端必须开始一个服务额可以创建一个PendingIntent为一个broadcast并且传递它给服务在通过启动服务的意图。这个服务可以使用broadcast发送结果。

多个请求启动服务的结果在多次调用服务的onStartCommand()。然而,你可以请求一个停止服务来停止它。

 

停止一个服务

一个服务必须管理自己的生命周期,这样系统不停止过销毁服务除非是系统必须回收内存并服务继续开始在onStartCommand()。所以,这个服务必须停止它自己调用stopSelf或其他组件调用stopService()。

一旦请求调用stopSelf和stopService来停止,这个系统就会尽快的销毁服务。

然而,假如你的服务同时执行多个请求通过onStartCommand(),然后你不应该停止服务当你正在处理一个请求,因为你也许会收到一个新的启动请求(正在停止是第一个请求可能会中断第二个)。为了避免这个问题,你可以使用stopSelf(int)来确认是停止最近的那个请求。当你调用stopSelf(int),你可以传递启动请求时的ID来停止你当前的请求。然后服务可以接受一个新的请求在你调用stopSlef(int),当id没有符合就不会被停止。

警告:这个很重要当你的应用停止它的服务当它工作的时候,为了避免浪费系统资源并且节约电量。如果有需要,其他的组件可以停止服务调用stopService.即使你启用绑定服务,你必须要是停止服务接收到调用onStartCommand。

更多的信息在服务的生命周期中,看下面管理生命周期的部分。

 

创建一个绑定的服务

一个服务允许应用组件绑定它调用bindService()为了创建一个长连接(一般不会允许组件启动它调用startService())

你应该创建一个服务当你想他和activity交互并组件在你的应用中或者暴露你的一些应用方法给另外的应用通过进程间通信(ipc)。

创建一个限制的服务,你必须实现onBind()调用方法返回一个IBinder这个定义了和服务间交流的接口。另外的应用组件可以调用bindService()恢复接口并开始调用方法在服务中。这个服务只活在应用调用它的组件中,当你没有组件绑定时系统会销毁它(你可以不需要停通过任何其他的方式停止服务但是服务是通过onStartCommand开始的)。

创建一个限制的服务,第一个需要做的事就是定义接口指定怎么样客户端和服务进行交流。你的接口服务和客户端都必须实现并且你服务必须从onBind返回。一旦客户端接收到IBinder,它可以开始和服务交流通过这个接口。

多个客户端可以绑定服务。当一个客户端交互和服务交互完后,他会调用unbindservice来解绑。一旦没有客户端绑定这个服务系统将会被销毁。

这里多个方式实现一个服务并且实现更多复杂的东西比启动一个service,所以客户端服务会单独出一个文档关于Bound Service。

发送通知给用户

一旦运行,一个服务可以发布一下用户事件比如 Toast Notifications or Status Bar Notifications.

         一个toast通知可以发送一个消息展示到一个当前窗口的表面然后消失,当一个状态栏提示提供一个图标在状态栏中的消息里,他可以让用户选择为了采取一些动作。

通常,一个状态通知最好的手法是当工作在后台完成(像下载一个文件完成)并且用户可以现在使用它。当一个用户选择通知在展开图里,通知可以启动一个activity。

 

运行一个服务在前端

一个前端的服务是一个服务被考虑到这个是用户主观意识因此不被系统杀掉到低内存时。一个前端服务必须提供一个通知为状态栏,这个被放置在表头上,这个的意思是通知不能被解散,除非服务要停止或从前台里移除。

比如一个播放器播放音乐在一个服务必须设置在前台,因为用户显示的意识到它的操作。这个通知在状态栏中指向当前的歌并且允许用户登录一个activity去和播放音乐交互。

请求一个你的服务运行在前端,只要调用startForeground()。这个方法有两个参数,一个是整数唯一标示通告并且提示在状态栏中。

 

注意:整数id你给出的不能是0

移除服务从前端只要调用stopForeground().这个方法带有一个布尔类型,指向是否可以移除状态栏的提示。这个方法不能关闭服务。到那时假如你关闭服务当它还在运行在前端时,通告就会被移除。

 

管理服务的生命周期

这个服务的生命周期时比activity简单。但是,它更重要当你注意到你怎样创建服务怎样被销毁,因为服务可以运行在后台不被用户注意到。

这个服务的生命周期从它的创建到销毁有两条不同的路:

1.      一个启动的服务:这个服务被创建当一个组件调用startService().这个服务可以指定运行并停止他自己调用stopSelf().一个组件可以停止服务调用stopService().当服务停止后,系统会销毁它。

2.      一个限制的服务:一个服务创建当一个组件调用bindService()。这个客户端可以和服务交流通过一个IBinder接口。这个客户端可以关闭连接当调用unbindService().多个服务端可以绑定同一个服务并且当所有的被解绑时,系统会销毁这个服务(系统不需要自己停止它)

 

这个两个方式并不是完全独立。这个可以绑定一个服务当它已经启动通过startService()。比如,一个后台播放音乐服务,可以启动调用startService()用一个Intent指定一个播放的音乐,晚点,可能当用户想操作一下控制播放器或者获取更多的信息关于当前的歌,一个activity可以绑定一个服务调用bingService。在这种情况下,stopService或者stopSelf都停止不了这个服务,知道所有的客户端都解绑。

 

实现这个生命周期回调函数

像一个activity,一个服务也有他的生命周期回调函数当你可以实现改变服务的状态并执行一些操作在合适的时间。接下来时服务的大概方法。

 

注意:不像activity的生命周期方法,你可以不调用他的父类实现方法。

 

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

1.      整个服务的生命周期必须在onCreate被调用并且结束在onDestroy返回之间。想一个activity,一个服务初始步骤也是onCreate()并且释放资源在onDestroy。比如一个音乐博士服服务可以创建在它的线程里播放音乐在onCreate 然后停止这个线程在onDestroy里。onCreate和onDestroy方法调用所有的服务,当他们被startService或者bindDervice调用时。

2.      这个活动的生命周期在服务开始的时候可以调用onStartCommand()或onBind()。无论哪个方法都持有一个意图传送给startService()或bingService().假如一个服务开启,活动生命周期被结束在同一个时间整个服务结束(这个服务仍然活着在onStartCommand()).假如服务被限制,这个周期将在onUnbind返回。

注意:即使开启一个服务被停止调用stopSelf或者stopService,这里没有相应的回调函数(没有onStop)所以,即使服务在客户端的范围里,系统销毁它当服务被停止。onDestro会被调用。

 

图2介绍一个回调方法为一个服务。虽然图中独立开了服务从startService从bindService服务,记住无论服务怎么启动的都可以绑定到客户端中。所以一个服务可以初始化用onStartCommand()仍然可以接受调用onBind()

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值