Service 官方详解(从官方文档翻译而来)

以下所有关于Service的解释都来源于Android官方英文文档大家都知道有的英文是不能够很好的翻译成中文的,如果硬是翻译过来可能就不是想要表达的哪个意思了,毕竟中文和英文还是有差距的。在者来说对于我这么一个高考语文刚考一半的人来说语言组织能力还是有待提高的啊大哭好了废话不说开始啦吐舌头


Service

服务是一个长期运行在后台不需要用户界面的应用程序组件。另一个应用程序启动服务,它可以继续在后台运行即使用户切换到另外一个应用程序。此外,一个组件可以绑定到一个服务上进行交互,甚至执行进程间通信(进程间通信)。例如,一个服务可以处理网络传输、播放音乐、执行文件的IO操作、于内容提供者交互,这所有的一切都是在后台执行的。


一个服务可以采取两种形式:

Started(启动)

当一个应用程序调用startService()方法时,服务就会启动。一旦这个服务开始运行,它就会在后台无限期的运行,即使启动它的组件被销毁了。通常,一个启动的服务执行一个单一的操作而且不会返回结果给调用者。例如,它可以在网络上上传或者下载一个文件。当这个动作执行完成的时候,服务应该停止。

Bound(绑定)

当一个应用程序调用bindService()方法是,服务就会被绑定。一个绑定的服务会提供一个客户端服务器接口,允许组件与服务进行交互,发送请求、接收返回结果,甚至在进行间通信。


虽然这些文档一般都会分别讨论这两种服务,你的服务可以用这两种方法一起运行-不但可以直接运行(无限期运行)也可以进行绑定。这是一个简单的你是否执行两个方法的问题:onStartCommand()允许组件启动它,onBind()允许绑定。


不管你的程序是启动它,绑定它,还是两个都用,任何一个应用程序组件都可以使用它(甚至从一个单独的应用程序),相同的任何一个组件都可以使用Intent通过activity启动它。然而,你可以在清单文件(AndroidMainFest.xml)里声明这个服务为私有的,从其他应用程序进行访问。更多信息请看Declaring the service in the mainfest


注意:

一个服务运行在它宿主进程中的主线程中---服务不会创建它自己的线程,也不会运行在一个单独的进程中(除非自己指定)。这就意味着如果你的服务是打算做一些耗CUP性能的操作或者一些阻塞交互的操作(例如播放MP3和网络任务),你应该在服务中开启一个新的线程做哪些事情。通过使用一个单独的线程,你可以减少应用程序无响应的风险(ANR:应用程序无响应),应用程序的主线程可以保持和用户继续进行交互。


The Basic(基础)

要创建一个服务,你必须创建一个Service的子类(或一个已经存在的子类)。在你的方法中,你需要重写一些回调方法处理Service生命周期的一些关键环节和提供一个组件绑定到服务的机制。你应该重写一下重要的回调用法:

onStartCommand()

当一个组件例如Activity通过调用startService()方法服务启动时系统会自动调用我们这个方法。一旦这个方法执行,这个服务就会在后台一直的运行着。如果重写了这个方法,你就有责任当任务结束后通过调用stopSelf()或者stopService()来停止这个服务(如果你想要一个绑定Service,就不需要重写这个方法)

onBind()

当应用程序通过调用bindService()想让一个组件和Service绑定时系统就会自动调用我们这个方法。如果你重写了这个方法,你就必须提供一个返回IBinder,用户可以和Service交互的接口。这个方法你必须实现,如果你不想要一个绑定的Service,该方法的返回值应该为null。

onCreate()

当Service第一次被创建的时候系统就会自动调用该方法,执行一次安装程序(在他不论是调用onStartCommand()或者是onBind()方法前)。如果这个服务早就已经在运行了,则这个方法就不会被调用。

onDestory()

当着个服务不再使用即将被销毁的时候系统自动调用该方法。你的服务应该重写这个方法清理一些资源,如线程、注册的监听事件、广播接收者等等,这个最后的服务接收调用。


如果一个组件通过调用startService()方法启动一个服务,这个服务将会一直运行直到它自己调用stopSelf()方法或者别的组件调用stopService()方法。


如果一个组件通过调用bindService()方法启动换一个服务(onStartCommand不会被调用),然后服务就会只让组件绑定到它,一旦服务从所有的客户端接触绑定,系统就会将服务销毁掉。


当系统的内存不够,Android系统会强制停止一个服务,它必须回收一些系统资源给正在与用户交互的Activity使用。如果服务是和一个正在和用户交互的Activit绑定在一起的,就不可能被回收掉,如果这个服务被声明在前台运行,那它将永远不会被杀死。否则,如果服务被启动并且长期运行,系统就会随着时间降低它在后台任务列表中的位置并且会变得很容易被杀死,然后你就必须设计让系统把它重新启动。如果系统杀掉了你的服务,当它的资源变得重新可用时系统就会重新启动它。跟多关于系统有可能杀死服务请点击Processes and Threading 。


以下部分,你可以看到如何创建每一种类型的服务和如何从另一个应用程序须使用它:

在清单文件里声明服务

和Activity一样,你必须在清单文件里声明所有的服务

在<application>标签中添加一个子节点<element> 如:


还有其他的属性,你可以在<service>元素中定义属性,例如,启动Service所需要的权限、该服务应该运行在哪个进程中。android:name属性是唯一必要的属性--它指定了服务类的名称 。一旦你发布了你的应用程序,这些名字就不该改了,如果你要改他们的话,就会破坏在一些明确要使用Service的地方的一些功能。


像Activity一样,一个服务可以定义意图过滤器,允许其他组件使用隐式意图调用服务。通过声明意图过滤器,从任何应用程序安装在用户设备上的元件可能会和你的服务声明一个意图过滤器相匹配的意图,另一个应用程序通过startservice()启动服务


如果你打算只在本地使用你的服务(其他的应用程序不能访问),就不要要提供任何意图过滤器。没有意图过滤器,你必须使用一个意图明确的服务类名字类启动服务。


此外,如果你将android:exported属性设置为false,你就可以确保在你的应用程序中你的服务是私有的,即使你的意图过滤器是有校的。


创建一个启动的服务

服务是一个组件通过调用startService()方法,在调用服务的onStartCommand()方法。


当一个服务启动时,它有一个生命周期是独立于启动它的组件并且这个服务是一直在后台运行的,即使启动它组件被销毁了。像这样的,当服务通过调用stopSelf()停止工作时服务就应该停止运行,或者另一个组件同坐调用stopService()是服务停止运行。


一个应用程序组件例如Activity可以通过调用startService()和传递一个Intent指定服务包括任何对服务使用的数据。服务在onStartCommand()方法里接收Intent。


例如,假如一个Activity需要保存数据到在线数据库。Activity可以提供一个绑定的Service通过一个意图调用startService()保存数据。服务在onStartCommand()方法中接受intent,链接到互联网并执行数据库事务。当事务结束的时候,服务停止并销毁。


注意:

默认情况下,服务运行在声明它的应用程序相同进程的主线程中。因此,当用户在同一应用程序中和Activit交互时,如果服务执行密集或者阻塞操作,服务将会减慢该Activity的性能。为了避免影响应用程序的性能,你应该在服务中心开辟一个线程。


传统上,有两类你可以创建一个启动的服务:

Service

这是所有服务的基类。当你集成这个类时,你创建一个新的线程来做所有的服务工作时很重要的,因为服务是运行在你应用程序的主线程中的,默认情况下,这会降低任何运行着的应用程序的性能。

IntentService

这是Service的子类,使用一个线程来处理所有的请求。这是最好的方式如果你的服务不要求同时处理多个请求。你要做的就是要实现onHandleIntent()方法,它接收每个请求的意图,所以你可以执行后台任务。


以下部分描述如何使用这些类的一个来实现你的服务:

继承IntentService 类

因为大多数启动的服务都不需要同时处理多个请求,使用IntentService可能是实现服务的最好方式。

IntentService做了以下事情:

1:创建一个默认的子线程和程序的主线程分割开,在onStartCommand()方法中执行所有传递过来的Intent

2:创建一个工作队列,每次传递一个Intent到你的onHandleIntent()方法中,因此不用担心多线程的问题。

3:当所有的请求执行完毕后服务会停止,不用我们自己调用stopSelf()

4:提供默认实现方法onBind(),并返回null

5:提供一个默认的onStartCommand()方法,发送意图到工作队列,然后在onHandleIntent()中实现

下面是一个继承IntentService的例子


这些是你必须实现的:一个构造函数、实现onHandleIntent()方法

如果你决定要重写这些回调方法,例如,onCreate()、onStartCommand()或者是onDestroy(),一定要调用父类的实现方法,因此,IntentService可以处理子线程的整个生命周期。

例如,onStartCommand()方法必须实现父类的方法



除了onHandleIntent()方法外,唯一一个不需要调用父类方法的是onBind()。


在下面的部分,你可以看到如果通过集成Service来实现相同种类的服务,但是如果你需要同时处理请求代码可能适当的多些。

继承Service类

就像你上面看到的,使用IntentService使你启动一个服务非常简单,然而,如果你的服务要执行多个线程,那么你就要继承Service来处理每个Intent.

作为对比,下面的代码就是继承Service实现和上面使用IntentService相同的任务。对每个启动请求,它使用一个子线程来实现,在一个时间只能有一个请求过程。


正如你看到的,这比使用IntentService多做了很多工作。

然而,因为你自己在onStartCommand()里处理每个请求,你可以同时执行多个请求。这并不是例子里描述的那样,但是如果你想那样做的话,你可以为每个请求创建一个线程并立即运行他们。


注意onStartCommand()方法必须返回一个整型的数值。这个整型的数值代表着系统杀掉它后该服务该如何继续运行。返回的值必须是下面的几个中的一个:

START_NOT_STICKY

如果系统在onStartCommand返回之前杀掉了服务,就不能重新创建服务,除非它们有挂起的意图传递。当不需要的时候或者当你的应用程序可以简单的重新启动完成没有完成的工作这是最简单的方法避免运行你的服务。

START_STICKY

如果系统在onStartCommand返回之前杀掉了服务,可以调用onStartCommand()创建服务,但是不传递最后的意图。而不是,系统用一个null的Intent调用onStartComand,除非有等待的意图启动服务,在这种情况下,这些意图将别传递。这适合媒体播放器(和类似的服务),不执行命令,但是不停的运行等待着工作。

START_REDELIVER_INTENT

如果系统在onStartCommand返回之前杀掉了服务,重新调用onStartCommandf创建服务并用最后一个意图传递到服务中。任何未处理的意图将会返回回来传递。这适合能积极的执行任务并立即回复的服务,例如,下载一个文件。


启动服务

你可以从一个Activity或者通过其他的应用程序的Intent通过startService()方法启动一个服务。Android系统调用系统的onStartComand方法并传递一个意图。

例如,上面我们例子中的HelloService就是通过startService()启动服务的。


startService()方法会立即返回并且Android系统会调用服务的onStartCommand()方法。如果这个服务没有运行,系统会先调用onCreate()方法,然后在调用onStartCommand()方法。


如果服务没有提供绑定,通过startService()意图传递是唯一的方式在应用程序组件和服务之间的通信。然而,如果你想要服务有一个结果返回,客户端可以用广播启动一个PendingIntent传递它到服务中并启动它。服务可以用广播接收一个返回值。


多个请求启动服务结果相应的会多次调用onStartCommand()方法。然而,只有一个服务请求停止服务就必须停止它。

停止服务

一个启动的服务必须管理它自己的生命周期。系统不会停止或者销毁服务除非系统必须恢复系统内存,服务依然在onStartCommand()方法之前运行。因此,服务必须通过stopSelf()或者其他组件通过调用stopService()停止它。


一旦请求通过stopSelf()或stopService()停止了,系统 会尽快的销毁这个服务。


然而,如果你的服务同时处理了多个onStartCommand()请求,当你处理完一个启动请你不应该停止服务,因为你可能会很快的收到一个新的启动请求。为了避免这种情况,你可以使用stopSelf(int)方法确保停止的这个服务就是最近启动的那个请求。当你调用stopSelf(int) 时,你会给你要对应停止的请求传递一个开始请求时的ID。如果你在能调用stopSelf(int)方法之前收到了一个新的启动请求,这个ID就不会被匹配且服务不会被停止。


注意:

当一个服务完成它自己的工作之后程序要停止该服务是很重要的,那可以避免系统资源的浪费和电池电量的耗损。如果需要,其他组件可以通过调用stopServie()停止服务。即使你启动了一个绑定服务,如果它收到了onStartCommand的调用你就必须要自己停止该服务。


更多关于服务的生命周期的Information,请移步Managing the lifecycle of a Service


创建一个绑定服务

绑定服务是允许应用程序组件通过调用bindService()绑定它并能长期运行的服务。


你应该创建一个绑定服务当你想从Activity中或者其他在你应用程序中的组件和服务交互并且暴漏一些功能给其他应用程序的时候,通过进程间通信。


创建一个绑定服务,你必须要实现onBind()方法返回一个IBinder,定义一个接口和服务进行交互。其他应用程序组件调用bindServie()方法检索接口并调用服务上的方法。这个服务只依附于和它绑定在一起的应用程序组件,因此,当没有组件和服务绑定在一起的时候,系统就会销毁该服务。


创建一个绑定服务,第一件你要做的事情就是定义一个接口指定客户端如何于服务进行交互。这个接口在客户和服务之间必须实现IBinder并且你的服务必须在onBind()方法中返回IBinder。一旦客户端收到IBinder,它就可以通过接口进行交互。


多个客户端可以一次绑定到服务上,当客户端和服务交互完成之后,要调用unbindService()方法进行解除绑定,一旦没有组件和服务进行绑定,系统就会销毁该服务。


有很多种方法实现绑定服务,这比启动一个服务要复杂的多,所以更过关于绑定服务请参Bound Services.


给用户发送一个通知

服务一旦运行,服务就可以使Toast Notifications或者 Status Bar Notifications 通知用户。

Toast 通知是一个一会会自动消失的出现在当前窗口表面的消息。Status Bar 通知会提供一个带有小图标的信息,用户可以点击这条信息(就像开启了一个Activity).


通常情况下,一个Status Bar 通知是最好的体现方式当一些后台任务完成之后,并且用户可以在通知上进行一些操作。当用户从扩张的视图上选择了通知,通知会启动一个Activity.


更多信息关于 Toast Notifications  和 Status Bar Notifications


在前台运行一个服务

一个前台服务是一个当用户意识到当系统的内存低时,不会被考虑当做被杀死的候选人的服务。一个前台服务必须使用Status Bar为用户提供一个通知,显示正在运行的标题,这就意味着这个通知不能够消失除非这个服务停止了或者从前台服务移除了。


例如,一个音乐播放器的服务应该是一个前台服务,因为用户要明确的知道他的操作。这个通知可能要标明正在播放的歌曲并且允许用户启动一个Activity和音乐播放器进行交互。


要求您的服务在前台运行,要调用startForeground()方法,这个方法由两个参数:整型的是通知的唯一标示符,另一个就是 Notification,例如:


注意:你给startForeground()传递的ID不能是0

如果要从前台移除服务,就要调用stopForeground(),这个方法需要一个Boolean值,来表示是否需要移除状态栏通知。这个方法不会停止服务。如果你要停止在前台运行的服务,那么这个通知也将会被移除。


管理Service 的生命周期

Service的生命周期要比Activity的生命周期短。然而,要关注Service是如何创建和如何销毁的也是很重要的,因为服务可以在没有意识的情况下在后台运行。

Service的生命周期--从创建到销毁--可以按照两个不同的路径

 ● 启动服务:当其他组件调用startService()时服务就会被启动,然后服务就会一直在运行你必须通过调用stopSelf()停止服务。另一个组件当然也可以同坐调用stopService()停止服务,当这个服务停止的时候,系统就会自动销毁它...

 ● 绑定服务:当其他组件调用bindService()时服务就会被启动,客户端通过IBinder接口和服务进行交互,客户端可以通过调用unbindService()方法关闭和服务的链接,多个客户端可以绑定到同一个服务上,当所有的服务都解除绑定的时候,系统就会自动回收掉该服务(服务不需要停止自己)。


这两个路径是完全不同的。 你也可以绑定一个早已通过startService()启动的服务。例如,一个在后台播放音乐的Service通过调用startServcie()启动并在后台不停的执行播放音乐。如果用户想练习下对音乐播放器的控制或者是当前歌曲的信息,我们就可以通过调用bindService()绑定一个Service。在这样的例子中,stopService()和stopSelf()都不能真正的停止服务,除非所有的客户端都已经解除绑定。


实现生命周期的回调方法

和Activity一样,服务也有要实现的生命周期回调方法,你可以实现这些方法监听服务的状态并在合适的时间执行工作。下面演示生命周期每个回调方法的骨架


^(* ̄(oo) ̄)^:这些回调方法和Activity不一样的是,你不需要在每个回调方法里面实现父类方法的实现


注:左边的图是使用startService()方法启动服务的,右边的图是使用bindService()启动服务的生命周期


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

1:服务的整个生命周期发生在onCreate()方法和onDestroy()方法别调用之间。和Activity一样,服务在onCreate()方法里初始化,在onDestroy()方法里释放所有的剩余资源。例如,一个播放音乐的服务可以在onCreate()方法里创建线程播放音乐,然后在onDestroy()方法里停止线程。

onCreate()方法和onDestroy()方法是所有的服务都要调用的,不论他们是通过startService()启动的还是通过bindService()方法启动的。

2:服务的活跃时间是在开始调用onStartCommand()或者onBind()方法开始。他们每个方法都要处理Intent不论他们是通过startService()启动的还是通过bindService()方法启动的。如果这个服务是运行的,当服务的整个生命周期结束的时候服务的活跃时间也就结束了。如果这个服务是绑定的,当onUnbind()方法返回时活跃时间就结束了。


注:尽管已经启动的服务是通过stopSelf()或者stopService()停止的,但是没有各自的回调方法停止他们。因此,除非服务是和组件绑定在一起的,当服务停止的时候系统就会销毁它---onDestroy()方法是唯一的接收回调。



上图说明了一个服务的典型回调方法。即使这个图将调用startService()方法启动和调用bindService()方法启动分隔开了,记住,任何服务,不管它是如何启动的,都在一定程度上允许客户端绑定它。因此,一个最初执行onStartCommand()方法的服务(客户端通过调用startService())依然可以收到onBind()的回调(当客户端调用了bindService())。


更过关于创建绑定服务的信息,请看 Bound Services 文档,包括更多关于onRebind()回调方法管理 Lifecycle of a Bound Service.


终于完了,累死的了 奋斗

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值