`

Services

阅读更多

Service 是这样一个组件,它能够在后台执行一个长时间的操作,并且不提供一个用户接口。其他的组件可以启动一个service并且它会一直运行咋后台background,即时用户切换到其他的应用程序。另外,一个组件可以绑定到一个serveice来与它交互,甚至执行进程内部交流interprocess communication(IPC)。例如,一个service可能处理网络事物,播放音乐,执行文件I/O,或者与一个content provider交互,全都是在后台执行的。

 

一个service基本上来说有两种形式:

 

Started

一个service的“started”状态从一个应用程序组件(例如一个activity)调用 startService() 开始。一旦启动了,这个服务就无限期地运行在后台,即时启动它的那个组件被销毁了。通常,一个启动的服务执行一个单独的操作并且不会返回结果给调用者。例如,它可能通过网络下载或者上传一个文件。当操作结束的时候,服务自己会停止。

 

Bound

一个service的“bound”状态从一个应用程序组件调用bindService()绑定它开始。一个绑定的service提供一个client-server接口,运行组件能够与它进行交互,发送请求,获得结果,甚至通过interprocess communication(IPC)做一些跨进程的操作。一个bound service只有在应用程序组件绑定到它上面的时候才运行。多个组件可以同时绑定到service上面,但是当所有的组件都unbind,这个service才会被销毁。

 

尽管这个文档大体上分开地讨论这两种类型的服务,但是你的服务可以同时以两种方式工作,它可以被Started(无限期地运行),也可以允许被绑定binding。你可以很简单地,通过是否实现一些方法:onStartCommand() 用来允许组件来启动它,onBind() 用来绑定它。

 

无论你的应用程序是started,bound,还是两种都有,任何应用程序组件可以使用这个service(即使来自不同的应用程序),与其它任何组件可以使用一个activity类似的,通过一个Intent 来启动它。然而,你可以在manifest文件中声明一个service是私有的,拒绝其它应用程序访问。这在Declaring the service in the manifest 章节中被讨论得更多。

 

注意:一个service运行在它的宿主进程hosting process的主线程main thread中--service并没有创建自己的thread,也并没有运行在不同的进程process中(除非你另有指定)。这就是说,如果你的服务要做任何CPU密集的操作或者阻塞操作(比如MP3重放或者网络操作),你应该在service中启动一个线程来做这些事情。通过使用不同的线程,你能够减少应用程序不响应Application Not Responding(ANR)错误,你的应用程序的主线程可以专注于你的由于用户交互的activities。(个人理解:service是运行在UI线程中的,所以你如果要做一些耗时的操作的话,还是要在service中另外开启一个thread来做,避免UI线程被卡住)

 

The Basics

Should you use a service or a thread?

************************************************

 

一个service是一个简单的组件,它能够运行在后台,甚至用户没有与你的应用程序交互。在这种情况下你应该创建一个service。

 

如果你需要在你的主线程main thread外面执行工作,但是只有当用户与你的应用程序交互,那么你应该创建一个新的thread而不是一个service。例如,如果你想要播放一些音乐,只有当你的activity正在运行,你可能在onCreate()中创建一个thread,在onStart()中开始运行它,在onStop()中停止它。也可以考虑使用AsyncTask 或者 HandlerThread ,而非传统的Thread 类。参考Processes and Threading 文档获取更多关于线程的信息。

 

记住,如果你使用了service,那么它默认始终运行在你的应用程序的主线程中,因此当它执行耗时的炒作的时候,你应该在这个service中启动一个新的thread。

 

************************************************

 

创建一个service,你必须创建一个Service 的子类(或者一个已经存在的子类)。在你的实现过程中,你需要覆盖一些回调方法来处理服务生命周期的关键方面,如果可能的话,为组件绑定服务提供一个机制。你要覆盖的最重要的回调方法是:

 

onStartCommand()

当其它组件,例如一个activity,通过调用startService() 请求启动service,这个方法就会被系统调用。一旦这个方法被执行,服务就开启了,并且在后台不断地运行着。如果你实现了它,在任务完成的时候,你有责任停止这个service,通过调用stopSelf() 或者stopService() 。(如果你只是想要提供绑定,你就不需要实现这个方法。)

 

onBind()

当其它组件想要通过调用bindService() 绑定bind这个服务(例如执行RPC),这个方法就会被系统调用。在你对这个方法的实现中,你必须提供一个接口,通过返回一个IBinder 使得clients用来与service进行交流。你必须总是实现这个方法,但是如果你不想被绑定,你应该返回null。

 

onCreate()

当服务第一次被创建的时候,系统会调用这个方法来执行一次性设置程序(在onStartCommand() 或者 onBind() 被调用之前 )。如果服务已经在运行,这个方法就不会被调用。

 

onDestroy()

当服务不再被使用或者被销毁的时候,系统会调用这个方法。你的服务需要实现它来清理资源,例如线程,注册的listeners,receivers等等。这是该服务能够接收到的最后一个调用。

 

如果一个组件通过调用 startService() 启动一个service(这会导致 onStartCommand() 被调用),那么service仍然运行着直到他调用自己的 stopSelf() 或者其它组件通过调用 stopService() 来停止他。

 

如果一个组件调用bindService() 创建一个服务(并且onStartCommand() 没有被调用),那么这个服务只有在组件绑定它的时候才运行。一旦没有任何clients绑定着这个服务,系统就会销毁它。

 

只有当内存过低的时候,Android系统会强行停止一个服务,以便将回收的系统资源分配给获得用户焦点的activity。如果service被绑定到一个获得用户焦点的activity,那么它最不可能被杀死,如果一个服务声明了运行在前台 run in the foreground (后面会讨论),那么它几乎不会被杀死。否则,如果一个服务启动了并且长时间地运行着,那么随着时间的推移,系统会降低它在后台进程列表中的位置,这个服务会变得很容易被杀死--如果你的服务被启动了,你应该将你的服务设计成能够很完美地被系统重新启动。如果系统杀死你的服务,当资源再次可用的时候,系统会尽快启动你的服务(尽管它也依赖于你从onStartCommand() 方法返回的值,后面会讨论 )。更多的关于什么时候系统可能销毁一个服务的信息,参考 Processes and Threading 文档。

 

在下面的章节中,你会看到你应该如何创建每种类型的服务和你该如何从其它应用程序组件中使用它。

Declaring a service in the manifest

像activities(和其它组件一样),你必须在你的应用程序的manifest文件中申明所有的services。申明你的service的方法是,在<application>标签中加入一个<service>子标签。例如:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

 你还可以在 <service> 标签中添加其它的属性来定义例如启动service的权限要求和service应该允许在哪个process等特性。android:name 属性是唯一要求的属性--它指定了service的类名。一旦你发布了你的应用程序,你不能改变这个名字,因为如果你这样做了,你可能会破坏一些明确的用来关联你的service的功能函数(参考博客Things That Cannot Change )。

 

参看<service> 标签,里面有更多关于在manifest文件中声明你的service的信息。

 

像一个activity一样,一个service可以定义一个intent filter让其他的组件通过使用隐式的Intent来调用service。通过声明intent filter,用户设备中所安装的任何的应用程序都可能启动你的service,如果你的service声明的一个intent filter符合其它应用程序传递给startService() 的intent。

 

如果你只打算自己使用服务(其他应用程序不使用它),那么你就不需要(也不应该)提供任何的intent filters。没有任何的intent filters,你必须通过使用一个确定名字来启动一个service。更多的关于starting a service 的信息接下去将会被讨论。

 

另外,你可以确保你的service对你的应用程序是私有的,只要你包含了android:exported 属性并设置为“false”。这样,即使你的service提供了intent filters,你的服务仍然是私有的。

 

更多的关于为你的service创建intent filters的信息,参考Intents and Intent Filters 文档。

Creating a Started Service

 

一个启动的服务started service是其他组件通过调用startService() ,导致调用onStartCommand()方法而启动的。

 

当一个服务被启动,它拥有一个独立于启动它的组件的生命周期,并且这个service能够不停地运行在后台,即使启动它的组件被销毁了。这样的话,当工作完成的时候,service需要调用stopSelf() 来停止自己,或者其它的组件通过调用 stopService() 也可以停止它。

 

一个应用程序组件,比如一个activity能够通过调用startService() 来启动一个服务,并且传递一个 Intent 给他,用来指定服务和包含这个服务需要使用的数据。服务在onStartCommand() 方法中接收这个 Intent

 

比如,假设一个activity需要保存一些数据到一个线上数据库中。这个activity可以启动一个service,并且将它要保存的数据通过Intent交给startService() 方法。服务在 onStartCommand() 方法中获取intent,连接到网络并执行数据库事务。当事务结束后,服务停止并销毁。

 

注意:默认的情况下,一个services运行在与应用程序同一个线程中,即声明它的那个应用程序主线程。所以,如果你的服务正在执行耗时或者阻断的操作,这个时候用户正在和这个应用程序中的activity进行交互,那么这个服务将会使得你的activity交互变得慢。为了避免影响应用程序的展现,你应该在服务中启动一个新的线程。

 

通常来说,有两个类你可以继承来创建和启动一个 started service:

 

Service

这是所有services的基本类。当你继承这个类,你要创建一个新的线程来做所有的工作,这点很重要,因为这个service使用的是你的应用程序的主线程main thread,也就是说,这会使得你的应用程序正在运行的任何的activity变慢。

 

IntentService

这个Service的一个子类,使用一个工作线程worker thread处理所有的发起请求,一次一个。如果你不要求你的服务同时处理多种请求,那么这是一个最好的选择。你所要做的是实现,用onHandleIntent() 方法 来接收每个请求发过来的intent,这样你就可以在后台进行工作了。

 

下面的章节描述了如何使用上面的类实现你的service。

Extending the IntentService class

因为大多数的started services不需要同时处理多种请求(事实上多线程是危险的),所以你最好使用 IntentService 来实现你的service。

 

IntentService 做了下面的事情:

 

 

  • 创建一个默认的工作线程worker thread用来执行所有发送给onStartCommand()的intents,让他们与你的应用程序的主线程分开。
  • 创建一个工作队列work queue一次传递一个intent给你实现的onHandleIntent()方法。所以你根本不用担心多线程的问题。
  • 在所有的启动请求被处理后停止服务,所以你不用调用 stopSelf()
  • 提供 onBind()的默认实现,返回null。
  • 提供onStartCommand()的默认实现,发送intent到工作队列work queue,然后到你的onHandleIntent()实现。

 

事实上所有你要做的是实现client提供的 onHandleIntent() 方法来完成工作。(尽管,你也需要为service提供一个小的构造器)

 

下面是一个实现IntentService的例子:

 

public class HelloIntentService extends IntentService {

  /** 
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      long endTime = System.currentTimeMillis() + 5*1000;
      while (System.currentTimeMillis() < endTime) {
          synchronized (this) {
              try {
                  wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
          }
      }
  }
}
 

 

上面就是你所要做的全部:一个构造器和一个 onHandleIntent()方法的实现。

 

如果你也决定覆盖其它的回调方法,例如onCreate()onStartCommand()onDestroy()请确保调用超类的实现,这样IntentService能够适当地处理工作线程的生命周期。

 

例如, onStartCommand() 必须返回一个默认的实现(intent如何被递交到 onHandleIntent()方法):

 

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    return super.onStartCommand(intent,flags,startId);
}
 

 

除了 onHandleIntent()方法,唯一不需要调用超类的方法是onBind(),但是如果你的服务允许被绑定,你只需要实现它。

 

在下一章节,你将看到,当继承自基本的Service类的时候,是如何具体实现的。这会有更多的代码,但是如果你需要同时处理开始请求start requests,这种做法可能更适合。

 

Extending the Service class

正如你再前面章节看到的,使用IntentService使得你实现一个started service变得非常简单。如果,然而,你要求你的service来执行多线程multi-threading(而不是通过一个工作队列来处理开始请求start requests),那么你可以继承Service类来处理每个intent。

 

 

为了比较,下面的代码例子是 Service 类的一个实现,用来执行明确的相同的工作正如上面例子中使用IntentService所做的一样。也就是说,对于每个开始请求start request,它使用一个工作线程worker thread,每次只处理一个请求,来执行工作和程序。

 

public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service.  Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block.  We also make it
    // background priority so CPU-intensive work will not disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();
    
    // Get the HandlerThread's Looper and use it for our Handler 
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);
      
      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }
  
  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); 
  }
}
 

正如你所看到的,这比使用IntentService要做更多的工作。

 

然而,因为你自己处理 onStartCommand()的每个调用,所以你可以同时执行多个请求。这不是这个例子所做的,但是如果那是你所想的,那么你可以为每个请求创建一个新的线程thread并马上运行他们(而不是等前一个请求完成后再执行)。

 

注意onStartCommand()方法必须返回一个整型。这个整型值描述了当系统杀死这个服务的这个事件发生后,该如何继续(正如上面讨论的,IntentService的默认实现为你处理了这些问题,尽管你可以修改它)。从onStartCommand()返回的值必须是下面常量中的一个:

 

START_NOT_STICKY

如果系统在onStartCommand()返回后杀死服务,没有重新创建服务,除非有新的intents来到。这是避免没必要的情况下运行你的服务,并且你的应用程序能够简单地重新启动未完成的工作最安全的选择。

 

START_STICKY

如果系统在onStartCommand()返回后杀死服务,重新创建了服务,并且调用了onStartCommand()方法,但是没有再递交最后的intent,而是系统调用onStartCommand()方法并返回一个null intent,除非有新的intent来启动这个服务,这样的话,这些intents被递交。这对media player(或者类似的服务)来说是合适的,他们不需要执行命令,但是要不断地运行着并等待工作。

 

START_REDELIVER_INTENT

如果系统在onStartCommand()返回后杀死服务,重新创建了服务,并且用最后递交给服务的intent来调用onStartCommand()方法。任何到达的intents被依次递交。这对积极执行工作并且立刻恢复的服务是合适的,例如下载一个文件。

 

更多关于返回值的信息,参考上面每个常量的相关文档信息。

 

 

Starting a Service

你可以从一个activity或者其它的应用程序组件通过传递一个IntentstartService()(指定要启动的服务)来启动一个服务。Android系统调用服务的onStartCommand()方法并传递那个Intent给它。(你不能直接调用onStartCommand()方法)

 

 

例如,一个activity可以通过startService()方法使用一个明确的intent来启动上面章节中的service例子(HelloSevice):

 

Intent intent = new Intent(this, HelloService.class);
startService(intent);
 

 

startService()方法立刻返回,并且Android系统调用服务的onStartCommand()方法。如果服务不在运行状态,系统会首先调用onCreate()方法,然后调用onStartCommand()方法。

 

如果服务也没有提供绑定,那么通过方法递交的intent是应用程序组件和服务之间唯一的交流方式。然而,如果你想让服务发送一个结果回来,那么启动这个service的client能够为broadcast创建一个PendingIntent(通过getBroadcast()),并且将它递交给启动服务的Intent。那么这个服务可以使用broadcast来传递一个结果。

 

多个请求来启动服务导致多次响应服务的onStartCommand()方法。然而,只有一个请求需要停止服务(通过stopSelf()stopService()

 

Stopping a service

一个started service必须管理它自己的生命周期。也就是说,系统不会停止或销毁这个服务,除非必须回收系统内存并且在onStartCommand()方法返回后,该服务继续运行。因此,服务必须调用stopSelf()方法来停止自己,或者其它组件通过调用stopService()方法来停止它。

 

 

一旦被使用stopSelf()或者stopService()来请求停止服务,系统会尽快地销毁服务。

 

然而,如果你的服务调用onStartCommand()同时处理多个请求,那么当你完成一个请求的时候,你不应该停止服务,因为你可能会接收到一个新的请求(在第一个请求结束的时候停止可能会中断第二个)。为了避免这个问题,你可以使用stopSelf(int)来确保你停止服务的请求总是基于最近的启动请求start request。也就是说,当你调用stopSelf(int)方法,你传递启动请求start request的ID与你停止请求stop request的ID相一致(startId传递给onStartCommand()方法)。那么如果服务在你能够调用stopSelf(int)方法之前接收的新的启动请求start request,那么这个ID就不会匹配服务就不会停止。

 

注意:当服务的任务完成的时候要停止这个服务,这很重要,为了避免浪费系统资源和消耗电池。如果必要的话,其他应用程序能够通过调用stopService()来停止服务。即使你能够绑定服务,如果你接收到一个onStartCommand()的调用,你必须总是要自己去停止这个服务。

 

更多的关于一个服务的生命周期的信息,参考下面的Managing the Lifecycle of a Service章节。

 

 

Creating a Bound Service

一个bound service是一个允许应用程序组件通过调用bindService()方法来创建一个长时间连接(并且通常来说不允许组件通过调用startService()方法来启动它)。

 

 

当你想要从你的应用程序中的activity或者其它的组件中与服务进行交互,或者希望将你的应用程序的功能通过interprocess communication(IPC)曝光给其它的应用程序,那么你应该创建一个bound service。

 

为了创建一个bound service,你必须实现onBind()回调方法来返回一个IBinder用来定义一个与服务进行交流的接口。那么其它应用程序组件可以调用bindService()方法来获得这个接口,并开始调用服务中的方法。服务只为绑定它的应用程序组件提供服务,所以当没有组件绑定这个服务的时候,系统就会销毁它(你不需要停止一个bound service,但是当服务通过onStartCommand()方法启动的时候,必须被自己去停止)。

 

为了创建一个bound service,首先你必须要做的是定义一个接口指定一个client如何与服务交流。服务和client之间的接口必须是一个IBinder的实现,并且是你的服务必须从onBind()回调方法返回的。一旦client接收到IBinder,它能够通过这个接口开始和服务交互。

 

多个clients可以同时绑定到一个service上。当一个client完成与服务的交互后,它会调用unbindService()来解除绑定。一旦没有clients绑定到服务,系统会销毁服务。

 

有多种方式来实现一个bound service,并且这些实现比一个started service要复杂得多,因此,将bound service的讨论放在了Bound Services文档中。

 

 

Sending Notifications to the User

一旦运行,一个服务能够使用Toast NotificationsStatus Bar Notifications来向用户通知事件。

 

 

一个toast通知是一个会出现在屏幕表面的提示,一会儿后就消失,一个状态栏通知在状态栏上提供了一个图标和一条消息,用户可以选中它来做一个操作(比如启动一个activity)。

 

通常来说,当后台工作完成后(比如一个文件完成下载)状态栏通知是最好的提示方式,并且用户可以对他进行操作。当用户从下拉视图中选中这个通知的时候,这个通知会启动一个activity(例如去查看下载好的文件)。

 

更多信息参考Toast NotificationsStatus Bar Notifications开发指导。

 

 

Running a Service in the Foreground

一个前台服务foreground service是一种用户所知道的服务,因此,当内存低的时候不会被系统杀死。一个前台服务必须在状态栏上提供一个通知,放置一个“正在进行”的标题,这意味着通知不能被关闭除非服务被停止或者被从前台移除。

 

 

例如,一个音乐播放器从service播放音乐应该被设置运行在前台,因为用户明确地知道这个操作。状态栏上应该有一个标明当前的歌曲的通知并允许用户来启动一个activity来与音乐播放器进行交互。

 

调用startForeground()方法来请求你的运行在前台的服务。这个方法有两个参数:一个整型值用来唯一标识通知和一个状态栏的Notification对象。例如:

 

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
        System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION, notification);
 

 

为了从前台移除服务,调用stopForeground()方法。这个方法有一个boolean值,这个值也标识着是否从状态栏上移除通知。这个方法没有停止服务。然而,当它还在前台允许的时候,如果你停止服务,这个通知也会被移除。

 

注意:startForeground()方法和stopForeground()方法在Android2.0(API Level5)后引入。为了实现在以前的平台上运行前台服务,你必须使用之前的setForeground()方法--参看startForeground()方法文档获取更多如何提高向后兼容性的信息。

 

更多关于通知的信息参考Creating Status Bar Notifications

 

 

Managing the Lifecycle of a Service

 

 

service的生命周期比activity的生命周期简单很多。然而,你更要密切注意你的service是如何被创建和销毁的,因为一个服务可以运行在后台却不为用户所知。

 

服务的生命周期--从它被创建到被销毁,有两种不同的路径:

 

 

  • A started service

 

当其他的组件调用startService(),这个服务被创建。这个服务不停地运行,必须通过调用自己的stopSelf()方法来停止它。其他的组件也可以调用stopService()方法来停止它。当服务停止后,系统会销毁它。

 

 

  • A bound service

 

当其他的组件(client)调用bindService()方法,这个服务就被创建了。client通过一个IBinder接口和service进行交互。client也可以通过调用unbindService()方法来关闭连接。多个clients可以绑定到同一个service上,当他们所有都解除绑定unbind,系统销毁服务。(service不需要自己停止)。

 

这两种路径不是完全分开的。也就是说,你可以绑定一个已经由startService()方法启动的服务。例如,一个后台音乐服务可以通过startService()方法启动,并用一个startService()标识要被播放的音乐。之后,用户可能想通过播放器来体验一些控制或者获取关于当前歌曲信息,一个activity可以通过调用bindService()方法来绑定到服务。这种情况下,stopService()方法或者stopSelf()方法实际上不能停止服务,直到所有的client解除了绑定。

 

 

Implementing the lifecycle callbacks

类似于一个activity,一个service也有生命周期回调函数,你可以实现这些方法来监听服务状态的改变并在适当的时候执行工作。下面的service框架说明了每个生命周期方法:

 

public class ExampleService extends Service {
    int mStartMode;       // indicates how to behave if the service is killed
    IBinder mBinder;      // interface for clients that bind
    boolean mAllowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

 

 

注意:不像activity的生命周期回调函数,你没有必要调用这些回调函数的超类实现。

 

 

这是服务的生命周期。图左边的部分展示的是使用startService()方法创建的服务的生命周期,图右边的部分展示的是通过bindService()方法创建的服务的生命周期。

 

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

 

一个service的完整的生命周期entire lifetime发生在onCreate()被调用的时候和onDestroy()返回的时候。像一个activity,一个service在onCreate()方法中进行初始化设置并且在onDestroy()方法中释放所有维护着的资源。例如,一个音乐重放service可以onCreate()方法中创建线程,在onDestroy()方法中停止线程。

onCreate()方法和onDestroy()方法被所有的服务所调用,无论他们是被startService()方法还是bindService()方法所创建。

 

一个service的激活的生命周期active lifetime开始于对onStartCommand()方法或onBind()方法的调用。每个方法各自处理传递给startService()方法或bindService()方法的 Intent。如果服务是启动类型(started)的,那么激活的生命周期active lifetime和完整的生命周期entire lifetime同时结束(甚至在onStartCommand()方法返回之后,服务仍然是激活的)。如果服务是绑定类型(bound)的,那么激活的生命周期active lifetime在onUnbind()方法返回的时候结束。

 

注意:尽管一个started service可以通过调用stopSelf()方法或stopService()方法来停止,但是没有各自属于自己的回调函数(即没有onStop()回调方法)。所以,除非服务绑定到一个client,当服务停止的时候,系统销毁它--onDestroy()方法是唯一接收到的回调方法。

 

上面的生命周期图是一个service的典型的回调方法。尽管图标将那些由方法创建的service和由方法创建的服务分开,记住,任何服务,无论他任何被启动,都有可能被client绑定。因此,一个通过onStartCommand()方法启动的服务(通过client调用startService()方法)仍然可以接收onBind()方法的调用(当一个client调用bindService()方法)。

 

更多的关于创建一个提供绑定的服务的信息,参考Bound Services文档,里面包含了更多Managing the Lifecycle of a Bound Service章节中onRebind()回调方法的信息。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 大小: 73.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics