使用Service前必须得读的好文

版权声明:吴延宝原创 https://blog.csdn.net/codeyanbao/article/details/81071879

Service(服务)

原文注释

A Service is an application component representing either an application's desire
 * to perform a longer-running operation while not interacting with the user
 * or to supply functionality for other applications to use.  Each service
 * class must have a corresponding
 * {@link android.R.styleable#AndroidManifestService <service>}
 * declaration in its package's <code>AndroidManifest.xml</code>.  Services
 * can be started with
 * {@link android.content.Context#startService Context.startService()} and
 * {@link android.content.Context#bindService Context.bindService()}.
 * 
 * <p>Note that services, like other application objects, run in the main
 * thread of their hosting process.  This means that, if your service is going
 * to do any CPU intensive (such as MP3 playback) or blocking (such as
 * networking) operations, it should spawn its own thread in which to do that
 * work.  More information on this can be found in
 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
 * Threads</a>.  The {@link IntentService} class is available
 * as a standard implementation of Service that has its own thread where it
 * schedules its work to be done.</p>
   etc...

Code Here

中文释义

简介

服务也是应用的一种组件,它被应用期望用来执行长耗时不需要和用户进行交互的操作和为其他应用程序提供基础的使用。每一个服务都需要在AndroidManifest中注册对应的Service标志。可以通过Context.startService()方法或者Context.bindService()方法启动一个服务。
注意服务和其他组件一样,运行在应用主进程的主线程中。这意味着你的服务中将要做一些很耗CPU的或者阻碍线程的操作,应该新启自己的工作线程去做这些事。IntentService类是标准的实现新启了自己的工作线程中去处理这些工作。

我们将从下面几个方面来讨论:

* 什么是服务?
* 服务的生命周期
* 权限
* 进程的生命周期
* 本地服务举例
* 远程管理服务举例

话题

什么是服务(what is service)

大多数关于服务类的疑惑是它不是什么:

一个服务不是一个独立的进程。服务对象不是表明它是运行在自己的进程中;除非有特殊说明,它和整个应用一样运行在同样的进程之中。服务也不是一个线程。在主线程中做一些工作处理不是一个方法(避免程序ANR错误)。

因此服务本身确实很简单,提供两个主要的功能:

  • 是应用告诉系统有些工作需要在后台做的一种能力(尽管用户没有直接的和应用进行交互)。对应着调用Context.startService方法告诉系统来安排service的工作,直到service或者哪个用户明确要停止service。
  • 是应用向其他应用暴露自己基础功能方法的一种能力。对应着调用Context.bindService来维持一个“长等待”连接着服务,为了能和服务进行交互。

当一个服务被创建了,出于上述原因,系统实际上就是初始化组件并且调用它的onCreate()方法和在主线程中其它的适当的回调。取决于服务实现的哪些回调方法,例如新建一个新的线程去处理后台任务。

因为服务本身是如此的简单,你可以和它简单的进行交互或者在你需要的时候去做很复杂的交互:把它当作本地Java对象来直接调用(正如LocalServiceSample中的说明),通过使用AIDL来提供一个远程的调用接口。

服务的生命周期(ServiceLifecycle)

这里有两个服务可被系统运行的原因。

  • 如果有人调用startService后,系统获取服务(创建服务并且调用它的onCreate()方法)然后client端传入参数调用onStartCommand方法。此刻开始服务便一直运行到stopService方法或者stopSelf方法被调用。注意如果多次调用startService会多此调用onStartCommand方法。无论调用了多少此startService,只要调用一次stopService或者stopSelf服务就会停止。然而服务可通过stopSelf确保服务不会被突然停止直到它的intents等任务处理完成后。对于启动服务,这里有两种主要的模式,取决于onStartCommand的返回值:START_STICKY是用来根据需要显示启动和停止的服务,START_NOT_STICKY或者START_REDELIVER被用于处理在发送给他们的任何命令时仍然运行的服务
  • Client端也能通过bindService获取一个持久化的于服务保持的连接。如果所需要创建的Service不在运行中的(没有其他Client端创建过),那么就会调用onCreate方法创建它,这种方式启动的Service并不会调用onStartCommand方法。Client端会从服务的onBind()方法返回中获取一个IBinder对象,而允许Client端通过该binder对象去调用服务的方法。服务会从建立开始一直运行(无论是否Client端持有服务的IBinder的引用)。通常返回IBinder对象是为了更复杂的需要写在AIDL中的接口。

一个服务能够在被多个Client同时绑定。基于此,系统将一直保持服务正常运行,只要服务被启动了并且有一个或者多个Client以Context.BIND_AUTO_CREATE的Flag保持着连接。一旦这两种条件不成立,服务的onDestroy方法将被调用,服务有效的终止。所有的清理任务(停止线程,注销)需要在onDestroy方法返回之前调用。

权限(Permissions)

可以在Manifest文件的Service Tag中强制申明访问权限。如果这么做,其他应用需要在自己的Manifest中通过uses-permission申明对应的权限,以便可以开启、停止或者绑定服务。

从Android2.3开始,通过startService启动服务时,可以通过设置Intent的Flag为FLAG_GRANT_READ_URI_PERMISSION或者其他权限。这样就能临时的授予服务相应的权限。对于这种方式启动的服务授权将一直保持到服务调用stopSelf(int)或者知道服务完全的停止了。这对没有申请保护权限的其他应用的服务授权访问权限同样起作用,甚至于其他服务根本没有设置允许被外部使用。

另外,服务可以通过checkCallingPermission方法来检查权限保护跨进程调用。

进程生命周期(ProcessLifeCycle)

Android系统将尽可能长时间的保持已经启动的服务或者有Client端绑定着的服务所在进程的生命。当运行时可用内存变的很低的时候,持有服务的进程的优先级将高于下面的情形:

  • 如果服务正在执行onCreate,onStartCommand,onDestroy方法,然后为了保证代码能够正常执行而不被杀死,服务所在的进程将会成为前台进程。
  • 如果服务已经被启动了,然后服务所在的进程将被认为优先级低于当前用户能看见UI的进程,但是比其他不可见进程的优先级更高。因为只有很少的进程对用户可见,这表明只有在内存极度少的情况下进程才会被杀死。然而,用户对后台进程没有直观的认识,在这种状态下,进程被认为是可杀的候选进程,所以你需要为这种情况的发生做好准备。特别是一个长耗时的服务将越来越有可能被杀,如果仍然启动长耗时的任务将保证被杀死(如果合适的话将重新启动)。
  • 如果有Client端和服务绑定,那么服务所在的进程将会比和它绑定的最重要的Client的重要性更高。也就是,如果和服务绑定的一个Client端是可见的,那么服务所在的进程将也被考虑是可见的。Client端的优先级能影响服务所在进程的优先级的方法可通过这些标志进行评判:BIND_ABOVE_CLIENTBIND_ALLOW_OOM_MANAGEMENTBIND_WAIVE_PRIORITYBIND_IMPORTANTBIND_ADJUST_WITH_ACTIVITY
  • 一个启动的服务可以通过**startForeground(int, Notifycation)**API来让服务处于前台进程的状态,系统将服务考虑为用户能感知的进程,这样在低内存状态下就不会成为被系统杀死的候选进程。(理论上在内存极端紧张的情况下服务还是可能被杀死,但是在实战中不必当成一个问题。)

综上表明,服务运行的大多数时间在内存紧张的情况下都将可能被系统杀死。如果真的发生了,系统将在稍后重启你的服务。如果你通过onStartCommand来异步实现一个计划任务,如果你正在处理任务的时候被杀了,你可能需要使用START_FLAG_REDELIVERY来让系统重新将intent发送给你以防止数据丢失。

与服务同一进程的其他组件(例如Activity)当然也能增加整个进程的重要性超过服务本身的重要性。

本地服务

服务最常见用途之一是作为应用程序的其他部分一起运行的辅助组件,和其他组件处在相同的进程中。除非另有明确说明,所有存在于一个.apk中的组件都是处在相同的进程之中,这是典型的一种情况。例子省略,请自行查阅。

远程服务

如果你需要写一个于远端进程的Client进行复杂通信(超出简单的使用startService来传送命令信息),你可以使用Messenger类代替去写完整的AIDL文件。使用例子请自行查阅。

猜你喜欢

转载自blog.csdn.net/codeyanbao/article/details/81071879