Android 教程 翻译 2 Services 服务 未完成

源:http://developer.android.com/guide/topics/fundamentals/services.html

翻译: Tonyfield

update: 2012.04.12

服务

快速浏览

  • 服务能运行在后台,即使用户在不同的应用程序也能进行工作
  • 服务能让其他组件与之绑定,另其他组件可与之交互及进行进程间通信
  • 服务默认运行在其所在应用程序主线程

文档主题

  1. 基础
    1. 在 manifest 中声明一个服务
  2. 创建一个启动的服务
    1. 扩展 IntentService 类
    2. 扩展 Service 类
    3. 启动服务
    4. 中止服务
  3. 创建 Bound 服务
  4. 向用户发送通知消息
  5. 在后台运行一个服务
  6. 管理服务的生命周期
    1. 实现生命周期回调

关键类

  1. Service
  2. IntentService

案例

  1. ServiceStartArguments
  2. LocalService

文章

  1. Multitasking the Android Way
  2. Android 2.0 开始 Service API 的变化

参见

  1. Bound 服务

  服务是一个应用程序组件,它可以在后台执行长期运行的操作,不提供用户界面。其他应用程序组件可以启动一个服务,服务持续在后台运行,即使用户切换到另一个应用程序。此外,一个组件可以绑定服务并与之交互,甚至通过IPC(进程间通信)与之交互。例如,服务完全可以在后台处理网络事务,播放音乐,执行文件I/O,或和内容提供商( content provider )交互。

  服务基本上可以采取两种形式:

  • 启动型(Stared)
    当应用程序组件(如活动)通过调用startService()启动一个服务时,则该服务是“启动型”的。一旦启动,服务可以无限期在后台运行,即使启动它的组件被销毁(也不影响)。通常启动型服务执行一个单一操作,也不会向其调用者返回结果。例如,它可能通过网络下载或上传文件。当操作完成后,服务应该自动停止。
  • 绑定型(Bound)
   当应用程序组件通过调用bindService() 绑定一个服务,则该服务是“绑定型”的。绑定型服务提供一个客户-服务器接口,以使得组件可与服务进行交互,发送请求,获取结果,甚至通过IPC(进程间通信)跨进程完成前述任务。一个绑定型服务仅当另一个应用程序组件绑定到它时开始运行。多个组件可以同时绑定到一个服务,但是当他们全部解绑,服务将被被销毁。

  尽管本文档分别讨论了这两类服务,您服务可以同时以两种方式工作 它可以是开始(无限期运行),也允许绑定。是否实现一对回调方法不算什么问题:onStartCommand()允许组件来启动它,onBind()允许绑定。

  不管是否应用程序是启动型的,约束的,或兼具两种类型,任何应用程序组件可以使用该服务(甚至一个单独的应用程序也可以),以同样的方式,任何组件都可以使用Intent 启动一个活动。然而,你能在manifest文件中声明服务为私有的,并阻止来自其他应用程序的访问。更多论述请参考在manifest中声明一个服务

注意: 服务运行在其宿主进程的主线程中 — 该服务即创建自己的线程,也运行在单独的进程中(除非你另行指定)。这意味着如果你的服务要做任何CPU密集型工作或阻塞操作(如MP3播放或访问网络),你应该在服务内创建一个新线程以完成这项工作。通过使用一个单独的线程,你会减少应用程序无响应(ANR)错误的风险,并且应用程序的主线程能保持活动专注于和用户的交互。

基础

你应该使用服务还是线程?

  简单地说,服务是一个能运行于后台的组件,即使在用户没有和你的应用程序交互。因而,你应该仅在需要它的时候创建服务。

  如果你需要执行主线程之外的工作,但只限于在用户和你的应用程序交互时进行,那么你可能应该创建一个线程而不是服务。,例如,如果你要播放一些音乐,那只会发生在你的活动正在运行时,你可以在onCreate()创建线程,在onStart()中启动这个线程,在onStop()中中止这个线程。还可以考虑使用AsyncTaskHandlerThread,代替传统的Thread 类。有关线程更多信息请参见进程与线程 文档。

  记住,如果你的确要使用服务,缺省地,它仍运行在你应用程序的主线程中,所以,当需要执行密集指令或阻塞操作,你仍应该在服务中创建一个线程。

  要创建服务,你必须创建 Service (或其已有子类)的子类。你需要在你的实现中覆盖一些回调方法,这些方法处理服务生命周期的关键环节,并适当地为组件提供一个机制来绑定该服务。最重要的回调方法,应该覆盖如下:

onStartCommand()
当另一个组件( 如一个活动 )通过调用 startService() 要求服务启动时,系统调用此方法。一旦此方法执行,服务启动并无限期运行在后台。如果你实现这个方法,你要做的是在工作完成时 ,通过调用 stopSelf()stopService() 中止该服务。(如果你只要提供绑定,你不需要实现此方法。)
onBind()
当另一个组件( 如执行RPC )要通过调用bindService() 和服务绑定时,系统调用此方法。要实现此方法,必须通过返回一个 IBinder ,它 提供客户一个接口以 和服务通信 。你必须实现此方法,但当你不允许绑定时你应该返回null。
onCreate()
当服务最初创建时, 系统调用此方法来 执行一次性设置设置过程( 在它调用onStartCommand()onBind()之前 )。如果服务已经在运行中,此方法不会被调用
onDestroy()
当不再使用并要销毁它时,系统调用此方法。你的服务应该实现它来清除所有资源,如线程,已注册的侦听器,接收器等。这是服务接受道德最后一个调用。

  如果一个组件通过调用 startService() 启动服务 (它返回以onStartCommand()调用结果),那么服务保持运行知道它调用stopSelf() 中止自己,或是另一个组件通过调用 stopService() 中止它。

  如果一个组件调用 bindService() 来创建服务 (并且onStartCommand() 没有被调用),那么该服务仅当组件与之绑定时运行。一旦服务从所有客户端解绑,系统就销毁它。

  Android 系统仅在内存偏低,并为有用户焦点的活动必须恢复系统资源的情况下,才会强制中止服务。如果服务被绑定到一个拥有用户焦点的活动,那么此服务不太可能被杀死,并且如果服务被声明为在后台运行(稍后讨论),那么它几乎永远不会被杀死。否则,如果服务被启动并长时间运行,那么系统将随时间逐渐降低其在后台任务列表中的位置,相对其他服务,它将更容易被系统杀死 — 如果你的服务是启动型,那么你必须妥善设计处理系统的重启。如果系统杀死你的服务,一旦再次满足资源条件( 这也依赖于onStartCommand()的返回值,稍后讨论),系统会重启该服务。关于系统何时可能销毁服务的更多信息,参见进程和线程 文档。

  以下章节你将了解如何创建每类服务,还有如何从其他应用程序组件使用它。

在manifest中声明一个服务

  像活动(和其他组件)一样,你必须在你的应用程序的manifest文件中声明所有服务。

  为了声明你的服务,加入一个 <service> 元素作为 <application> 元素的子节点。例如:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>
  你还可以在 <service> 元素中包含其他属性,例如要求启动服务应当运行服务的进程的许可。android:name 属性是唯一必须的属性 — 它指出服务类名。一旦你发布你的应用程序,就不能改变这个类名,否则,可能会破坏一些功能,这些功能使用明确intents来引用你的服务(参阅博文 ThingsThat Cannot Change)。

  关于如何在manifest文件中声明服务的更多信息参见<service> 元素参考文档。

  就像活动那样,服务也能定义intent filters,以允许其他组件通过隐含intents来调用服务。当你的服务声明的 intent filter 匹配另一个应用程序传递给startService()intent ,通过声明intent filters,任何安装在用户设备上的应用程序组件都有可能启动你的服务

  如果你仅需在本地使用你的服务 (即其他应用程序不会使用它),那么,你不需要(也不应该)提供任何 intent filters。不带任何 intent filters,你必须使用一个显式命名服务类的intent启动服务。更多关于启动服务 的内容稍后讨论。

  而且,仅当你包 android:exported 属性为"false"时,你才能保证服务对于应用程序是私有的。这即使当服务提供 intent filters时都是有效的。

  关于为你的服务创建 intent filters 的更多内容参见 Intents and Intent Filters 文档。

创建一个启动型服务

  启动型服务由另一个组件通过调用 startService()来启动, 返回对服务onStartCommand()方法的调用。

  当一个服务启动,它的生命周期独立于启动它的组件,并且该服务无限期运行在后台,即使启动它的组件已经被销毁。因此当服务完成工作,应该通过调用stopSelf() 来中止自身,或者由另一个组件调用stopService()来中止它。

  一个应用程序( 如活动 )能通过调用 startService() 启动服务,传递一个指定该服务和包含任何数据的Intent 服务使用。该服务在onStartCommand()方法中接收这个Intent

  例如,假设一个活动需要保存一些数据到一个在线数据库。该活动能启动一个伴随服务( companion service ),并且通过传递intent给startService()将要保存的数据传递给该服务。服务在onStartCommand()中接收到intent,连接到互联网进行数据库事务。当事务完成,服务中止自身并被销毁。

注意: 服务默认运行在应用程序声明的相同进程中,即应用程序的主线程。因此,如果你的服务正在进行密集型或阻塞操作,而你的用户也正和同一个应用程序的活动交互时,服务会降低活动性能。为避免对应用程序性能的影响,你应该在服务中启动一个新的线程。

  传统上有两个类供你扩展创建一个启动型服务:

Service
这是所有服务的基类。当你扩展这个类,在其中创建一个新线程来处理所有服务工作是很重要的,因为服务默认使用你应用程序的主线程,那将降低在应用程序中运行的所有活动的性能。
IntentService
这是 Service 的子类,它使用一个工作线程来处理所有启动请求,一次一个。如果你不需要你的服务同时处理多个请求,这是最好的选择。所有你需要做的是实现onHandleIntent(),它接收 intent 代表的每个启动请求,以便你能处理后台工作。

  以下章节论述如何用一个或多个服务类(或其子类)实现服务。

扩展 IntentService 类

  因为很多启动型服务不需要同时处理多个请求(那其实是一个危险的多线程情况),用IntentService实现你的服务可能是最好的。

  IntentService 完成以下工作:

  • 创建默认工作线程,它执行所有从你应用程序主线程发给 onStartCommand() 的 intents 。
  • 创建一个工作队列,它一次传递一个 intent 给你实现的 onHandleIntent() 方法,所以你不必担心多线程问题。
  • 在所有启动请求得到处理后中止服务,所以你不必调用 stopSelf()方法。
  • 提供缺省 onBind() 方法实现,它返回 null 。
  • 提供缺省的 onStartCommand() 方法,它传递 intent 给工作队列,再到你实现的onHandleIntent()

  所有这些说明一个事实,你要做的全部事情是实现 onHandleIntent() 以完成客户提供的工作。( 虽然你还需要为服务提供一个小小的构造函数。)

  下面是实现 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基类实,这需要更多代码,但比较适合需要同时处理启动请求的场合。

扩展 Service 类

  如你在上节所见,使用 IntentService 实现一个启动型服相当简单。但如果你需要服务处理多线程 ( 不同于通过工作队列处理启动请求),那么你能扩展Service 类来处理每个 intent。

  作为比较,以下例程实现一个Service 类,它完成的工作和上面使用IntentService实现的服务完全相同。也就是说,对于每个启动请求,它用一个工作线程进行处理,一次仅处理一个请求。

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() 的调用,你能同时处理多个请求。虽然这不是这个例子要做的,但如果你需要这么做,你可以为每个请求创建一个新线程并立刻运行它们 (而不是等待前一个请求完成).

  注意,onStartCommand() 方法必须返回一个整数。这个返回值表示,如果发生系统杀死该服务事件,系统应该如何继续处理该服务,(如上面讨论,IntentService 的默认实现帮你处理这个事件)。onStartCommand() 返回值必须是一下常量之一:

START_NOT_STICKY
onStartCommand() 返回后,如果系统杀死该服务,除非有挂起的 intent 要传送,否则不重建该服务。如果你的应用程序可以简单重启任何未完成的任务,这是避免不必要运行服务最安全的选项。
START_STICKY
onStartCommand() 返回后,如果系统杀死该服务,重建服务并调用onStartCommand(),但不再传递最终的intent。相反,系统用null 作为intent调用onStartCommand()的参数,除非有等待的 intents 来启动服务,此情况下,那些 intent被传递给onStartCommand()。这个参数适合媒体播放器 (或类似服务) ,它不需要执行命令但需要无限期运行并等待一个任务。
START_REDELIVER_INTENT
onStartCommand() 返回后,如果系统杀死该服务,重建服务并调用onStartCommand(),将最终 intent 作为传递给它的参数。所有等待的 intents 被顺序传送。这个参数适合服务实际执行一个应该被立即恢复的任务,如下载一个文件。

  了解这些返回值详细信息,参见这些常数参考文档链接。

启动服务

  可以从一个活动或其他应用程序组件来启动服务,调用startService(),带Intent参数,指定要启动的服务。然后Android 系统调用服务的 onStartCommand() 方法并传递参数Intent 。( 你不应该直接调用onStartCommand() )

  例如,在前面章节中,一个活动能使用startService()带一个显式 intent 参数来启动服务例程(HelloSevice):

Intent intent = new Intent(this, HelloService.class);
startService(intent);
  startService() 方法立即返回,之后Android 系统就调用服务的 onStartCommand() 方法。如果服务尚未运行,系统首先调用 onCreate(),然后调用 onStartCommand()

  如果服务也不提供绑定,那么 startService() 传递的intent参数是应用程序组件和服务间唯一的通信模式。但是,如果你要服务返回结果,那么启动服务的用户可以创建PendingIntent 作一个广播(用getBroadcast()),传递给它服务,在Intent 中启动服务。服务于是可以用广播来传送一个结果。

  多个启动服务的请求导致多个对应对服务的onStartCommand()的调用。但是,只有一个中止服务请求 (用 stopSelf()stopService()) 被要求中止它。

中止服务

  一个启动型服务必须管理自己的生命周期。也就是说,除非系统不得不恢复系统内存,否则不会停止或销毁该服务,服务在onStartCommand() 返回后持续运行。所以,服务必须调用 stopSelf() 中止自己,或由其他组件通过调用stopService() 中止它。

  一旦用 stopSelf()stopService(),提出中止的请求,系统会尽快销毁服务。

  但是,如果你的服务在 onStartCommand()同时处理多个请求,那么当你完成一个启动请求的处理后不应该中止服务,因为那时起你可能已经接收到一个新的启动请求 (在第一个请求结束时中止将中断第二个请求)。为了避免这个问题,你可以使用stopSelf(int) 来确保你总是基于最近的启动请求来中止服务。也就是说,当你调用 stopSelf(int),你传递启动请求的 ID  ( 传递给 onStartCommand()的那个启动 id ) 给你的中止请求对应的服务。那么,如果服务在你能调用stopSelf(int)前接收到一个新的启动请求,则该 ID 将不会匹配,服务也就不会中止了。

(译注:可能存在启动请求队列,通过在队列追加中止请求来中止服务,而不是直接中止服务,这样,如果队列前面还有请求,服务继续处理。中止服务请求不是队列中唯一的请求,它带有的 ID 自然失效,这样防止服务在还有请求时被中断)。

注意: 重要的是,你的应用程序要在完成工作时中止其服务,以避免浪费系统资源和消耗电池能量。如果需要,其他组件可以调用stopService()中止服务。即使你启用绑定服务,只要它收到过对onStartCommand()的调用,你也必须自己来中止该服务。

   关于服务生命周期的内容,参阅后面章节 管理服务的生命周期

创建绑定型服务

  绑定型服务A bound service is one that allows application components to bind to it by callingbindService() in order to create a long-standing connection(and generally does not allow components tostart it by calling startService()).

  创建一个绑定型服务的场合一般有两种,或者你的应用程序中的活动及其他组件需要和服务交互,或者需要将应用程序的功能通过进程间通信(IPC)暴露给其他应用程序。

  为创建一个绑定型服务,你必须实现onBind() 回调方法,它返回一个IBinder 定义和服务通信的接口. Other application components can then call bindService() to retrieve the interface andbegin calling methods on the service. The service lives only to serve the application component that is bound to it, so when there are no components bound to the service, the system destroys it(you donot need to stop a bound service in the way you must when the service is startedthrough onStartCommand()).

  为创建一个绑定型服务,你要做的第一件事是定义接口,以指定客户怎样和服务通信。服务和客户之间的接口必须是IBinder 实现,这个参数由onBind() 回调方法返回。一旦客户收到IBinder,它就可以开始通过这个接口和服务交互。

  服务可以被多个客户马上绑定。当一个客户完成和服务的交互,它调用 unbindService() 来解绑。一旦没有客户绑定服务将被系统销毁。

  有多种方法可以实现一个绑定服务,该实现比一个启动型服务更复杂,所以专门提供单独文档Bound Services 来讨论绑定服务。

向用户发送通知

  一旦运行,服务能用 Toast提示状态条提示通知用户事件。

  吐司提示消息出现在当前窗口上层,一段时间后即消失,而状态条提示在状态条上显示一个图标表示有消息,用户可以选取图标来采取行动 (例如,启动一个活动)。

    

     图1-1 Toast 提示                                                       图1-2 状态条提示                    图1-3 扩展的状态条提示

  通常,状态条提示是最好的技术手段,当后台工作完成时(例如,一个文件下载完毕) 用户即可采取行动。当用户从扩展视图选取提示 ,提示可以启动一个活动 (如查看下载文件)。

  更多内容参见 Toast提示 状态条提示 开发者指南。

在后台运行一个服务

A foreground service is a service that's considered to be something theuser is actively aware of and thus not a candidate for the system to kill when low on memory. A foreground service must provide a notification for the status bar, which is placed under the"Ongoing" heading, which means that the notification cannot be dismissed unless the service iseither stopped or removed from the foreground.

For example, a music player that plays music from a service should be set to run in theforeground, because the user is explicitly awareof its operation. The notification in the status bar might indicate the current song and allowthe user to launch an activity to interact with the music player.

To request that your service run in the foreground, callstartForeground(). This method takes two parameters: an integerthat uniquely identifies the notification and theNotification for the status bar. For example:

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);
To remove the service from the foreground, callstopForeground(). This method takes a boolean, indicatingwhether to remove the status bar notification as well. This method doesnot stop theservice. However, if you stop the service while it's still running in the foreground, then thenotification is also removed.

Note: The methods startForeground() andstopForeground() were introduced in Android 2.0 (API Level5). In order to run your service in the foreground on older versions of the platform, you mustuse the previoussetForeground() method—see thestartForeground() documentation for information about howto provide backward compatibility.

For more information about notifications, see Creating Status BarNotifications.

管理服务的生命周期

  服务的生命周期比活动生命周期简单很多。但是,你更你需要注意你的服务如何创建和销毁的,因为服务可以不为用户知觉在后台运行。

  服务生命周期 — 从其被创建到其被销毁 — 可以经由以下两种不同路径:

  • 启动型服务

    其他组件调用 startService()时,启动型服务即被创建。服务于是无限期运行,并且必须调用stopSelf()中止自己其他组件也能调用stopService() 中止该服务。服务中止后系统就会销毁它。

  • 绑定型服务

    其他组件(客户)调用bindService() 时,绑定型服务即被创建客户于是通过一个IBinder 接口和服务通信。客户也可调用 unbindService()关闭连接。多个客户可以绑定同一个服务,当他们全部解绑服务系统销毁这个服务。( 这里,服务不需要中止自己)

  这两种途径并不是完全分离的。也就是说,你可以绑定以 startService()启动的服务。例如背景音乐服务可以startService() 来启动,带有的参数Intent 能指出要播放的音乐。之后用户可能要进行一些对播放器的控制或需要获取当前歌曲的信息,一个活动能通过调用bindService()绑定该服务。在类似这种情况下,在所有客户解绑前,stopService()stopSelf() 实际不会中止该服务。(Android Pro4 中建议开发者不要同时使用这两种服务方式,由于它们预定义的生命周期不同,混合使用将给自己造成不必要的麻烦。)

实现生命周期回调方法

  类似活动,服务也有能实现的生命周期回调方法,来监测服务状态的变化,并在合适的时间执行工作。以下框架展示每个生命周期方法:

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
    }
}


注意:不像活动生命周期回调方法,你不需要调用这些回调方法的父类实现。

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

注意: 启动型服务可以通过调用 stopSelf()stopService()来中止,但没有对应回调方法提供 (不存在onStop() 回调方法)。因此,除非服务绑定到某客户,否则系统在服务被中止时就会销毁它 — onDestroy() 是唯一能接收的回调方法。

 

图 2. 服务生命周期。左图显示用startService()建立的服务生命周期;右图显示用bindService()建立的服务生命周期。

  图2描述典型的服务回调方法。虽然该图区分了由 startService()bindService()创建的服务, 但要记住,无论服务怎样被创建,它都允许客户绑定它。所以,一个开始以 onStartCommand() 启动的服务 ( 客户调用startService() ) 仍能接受对onBind() 的调用 (当客户调用bindService())。

  更多关于创建提供绑定服务的信息,参见 绑定型服务 文档,其中管理绑定型服务的生命周期 章节包含更多关于onRebind() 回调方法的知识


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值