Android 组件Service 详解总结,Thread

本文详细介绍了Android Service的概念、类型、生命周期管理、与Activity的交互方式以及如何提高Service的优先级。主要内容包括Service的启动与停止机制、支持绑定与非绑定模式、通过Intent进行通信、以及如何在后台持续运行服务而不影响应用性能。

写在前面:在阅读本文章前我假设你有良好的JAVA基础,并对Android的基础知识已经有一定的了解,如果没有达到要求请跳过这篇文章。以下内容来自官方API User Guides翻译以及网友们的总结概括。

简要介绍说明一下Service

一个Service也是一种应用程序组件,它运行在后台以提供某种服务,通常不具有可见的用户界面。其它的应用程序组件可以启动一个Service,即使在用户切换到另外一个应用程序后,这个Service还是一直会在后台运行。此外,一个应用程序也可以绑定到一个Service然后使用进程间通信(IPC)方式与Service之间发生交互。例如一个Service可以处理网络事物,播放音乐,读写文件或者读写ContentProvider,所以这些都在后台运行。

一个Service可以以以下两种形式存在:

· Started(启动)
在一个应用程序以startService() 来启动一个Service时,这个Service将处于“Started”状态。一旦启动,这个Service可以在后台一直运行下去,即使启动它的应用程序已推出。通常,一个处于“started”状态的Service完成某个功能而不会给启动它的应用程序组件返回结果。比如,这个服务(Service)可能是上载或是下载一个文件,当任务完成后,服务自行退出。

· Bound (绑定)
当一个应用程序组件以bindService() 绑定一个Service时,这个Service处于“Bound”状态。处于“Bound”状态的Service提供了一个客户/服务(C/S)调用接口支持其它应用程序组件和它交互,比如发生请求,返回结果,或者使用IPC完成跨进程间通信。一个处于“Bound”的Service只能和与其绑定的应用程序一起运行。多个应用程序组件可以绑定到同一个Service。当所有绑定的应用程序组件都退出绑定后,被“绑定”的Service将被销毁。

对于一个Service来说,它可以是“Started”,“Bound”或者同时处于两种状态。其它任一应用程序组件(比如一个Activity)都可以使用这个Service,即使其它应用程序组件是在不同的应用程序中。当然你可以把Service定义为私有的,这样其它应用程序就无法使用你定义的Service。

要注意的是,一个Service运行在其宿主进程的主线程中--服务不会自己创建新的线程也不运行在独立的进程中(除非你特别指明)。这意味着,如果你的Service需要完成一些很耗CPU资源的操作(比如播放MP3,或者使用网络),你应该在Service中创建新的线程来完成这些工作,从而降低出现程序无响应(ANR)的风险。

讲到这就不得不说一下Service和Thread那点事了(他俩没关系)

1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。
2). Service:Service 是Android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!

既然这样,那么我们为什么要用 Service 呢?其实这跟 Android 的系统机制有关,我们先拿 Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。

举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。

因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。

Service基础
要创建一个Service,你必须从Service或是其某个子类派生子类。在你的Service子类实现中,你需要重载一些方法以支持Service重要的几个生命周期函数和支持其它应用组件绑定的方法。下面给出几个需要重载的重要方法:

· onStartCommand()

Android系统在有其它应用程序组件使用startService()请求启动Service时调用。一旦这个方法被调用,Service处于“Started”状态并可以一直运行下去。如果你实现了这个方法,你需要在Service任务完成时调用stopSelf()或是stopService()来终止服务。如果你只支持“绑定”模式的服务,你可以不实现这个方法。

· onBind()

Android系统中有其他应用程序组件使用bindService()来绑定你的服务时调用。在你实现这个方法时,你需要提供一个IBinder接口以支持客户端和服务之间通信。你必须实现这个方法,如果你不打算支持“绑定”,返回Null即可。

· onCreate()

Android系统中创建Service实例时调用,一般在这里初始化一些只需单次设置的过程(在onStartCommand和onBind()之前调用),如果你的Service已在运行状态,这个方法不会被调用。

· onDestroy()
Android系统中Service不再需要,需要销毁前调用。在你的实现中你需要释放一些诸如线程,注册过的listener,receiver等,这是Service被调用的最后一个方法。

如果一个Service是由startService()启动的(这时 onStartCommand()将被调用),这个Service将一直运行直到调用stopSelf()或其它应用部件调用stopService()为止。

如果一个部件调用bindService()创建一个Service(此时onStartCommand()不会调用),这个Service运行的时间和绑定它的组件一样长。一旦其他组件解除绑定,系统将销毁这个Service。

Android系统只会在系统内存过低且不得不为当前活动的Activity恢复系统资源时才可能强制终止某个Service。如果这个Service绑定到一个活动的Activity,基本上不会被强制清除。如果一个Service被申明成“后台运行”,就几乎没有被销毁的可能。否则的话,如果Service启动后并长期运行,系统将随着时间的增加降低其在后台任务中的优先级,其被杀死的可能性越大。如过你的Service是做为“Started”状态运行,你必须设计后如果在系统重启服务时优雅退出。如果系统杀死你的服务,系统将在系统资源恢复正常时重启你的服务(当然这也取决于onStartCommand()的返回值)。

在Manifest中申明Service

和Activity一样,你必须在Manifest文件中申明应用中使用到的Service。为了声明一个Service,你需要定义的子元素,比如:

1
2
3
4
5
6
7
<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

Service还包括一些其它属性,android:name是唯一一个必须定义的属性,它定义了Service的类名。

和Activity一样,你可以为Service定义Intent Filter以支持其它部件隐式调用该服务。如果你只打算在你自己的应用中使用某个Service,那么就不要定义任何Intent Filter。在这种情况下,你必须明确指明Service的类名来启动这个Service。此外,你可以通过设置android:exported属性为false来明确说明该Service为私有,即使你为Service定义了Intent Filter ,其它应用也无法使用你的Service。

创建一个“Started”的Service
当其它应用程序组件使用startService()来启动Service后,这个Service就成为“Started”的Service。这时Service的onStartCommand () 回调函数将会被调用。

当一个Service以startService()启动后,处于“Started”状态,其生命周期独立于启动这个Service的其它应用程序组件,并且可以在后台无限期运行,即使启动它的其它应用程序组件已经退出。在这种情况下,Service可以调用stopSelf()或者其它程序部分调用stopService()来结束这个Service。

一个应用程序组件比如一个Activity可以通过传入Intent使用startService()来启动一个Service,这个Intent指明需要的服务并包含了Service需要的数据。Service在onStartCommand回调函数中可以访问这个Intent。

要注意的是,Service缺省和申明它的应用程序使用同一个进程并且运行在主线程中,因此如果你的Service比较耗时的话,那么这个Service会影响到应用的用户响应性能。为避免这种现象,你应用在Service中创建新线程。

你可以使用下面两个基类来创建一个“Started”的Service。

·Service 这是所有Service的基类,当你派生这个类时,使用新创建的线程来完成Service需要完成的工作非常重要,这是因为Service缺省也会使用你的应用程序的主线程,这可能会影响你应用程序的响应性能。

·IntentService 为Service的一个子类,它会使用一个工作线程来处理所有的请求,每次处理一个请求。这在你无需实现并行处理多个请求时是最好的选择。你只需重载onHandleIntent()方法,这个方法接受每个请求,从而你可以在后台完成所需任务。

派生IntentService类(这个你要重点了解)
因为大部分“Started”的Service不需要并行处理多个请求,这时最好的选择是派生自IntentService。

类IntentService可以完成以下工作:

·创建一个工作线程来处理所有发送到onStartCommand()的请求(Intent),从而和应用的主线程分开。

·创建一个工作队列来逐个处理每个请求,从而无需考虑多线程编程。

·在处理完所有请求后中止Service的运行,你无需调用stopSelf()来终止Service。

·提供onBind()的缺省实现,返回null。

·提供onStartCommand()的缺省实现,将接受到的Intent发送到工作队列中,然后调用你的onHanleIntent()实现。

因此,对于你来说,只需要提供onHandleIntent()来处理发过来的Intent,当然你可能需要实现Service的一个简单的构造函数。

下例为IntentService的一个简单实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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(),你必须返回基类的onStartCommand()的返回值,这样Intent能够传递到onHandleIntent()的原因:

1
2
3
4
5
@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类
从上面可以看到使用IntentService可以让实现“Started”的Service变的非常简单,然而如果你需要支持使用多线程并行处理多个请求(而非使用工作队列来依次处理请求),这时你就需要从Service类来派生。

作为比较,下面的例子使用Service实现和上面使用IntentService同样的功能,也是使用一个工作线程来逐个处理每个请求,可以看成是IntentService的一个实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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()方法必须返回一个整数,这个返回值定义了如果Android系统在杀死这个Service后又需要使用这个Service后的行为。这个返回值可以有下面几种情况:

· START_NOT_STICKY 如果Android系统在onStartCommand() 返回后杀死了这个Service,系统不会重新创建这个Service,除非它是一个Pending Intent。这是在你的应支持简单的重启没有完成的任务避免无必要的Service运行时ic最好的选项。

· START_STICKY 在Android系统在onStartCommand () 返回后,选择重新创建这个Service并调用Service的onStartCommand () 方法,但不会重新发送上一次的请求。Android系统使用空Intent调用onStartCommand,除非它是一个PendingIntent。这种情况适用于一些媒体播放器服务。

· START_REDELIVER_INTENT在Android系统在onStartCommand() 返回后,选择重新创建这个Service并调用Service的onStartCommand () 方法,并且重新发送上一次的请求。这适用一些比较活跃地进行某些工作的服务,需要立即恢复活动比如下载文件的服务。

启动Service

在Activity或是其他应用程序组件可以通过传递Intent调用startService()方法来启动一个Service。Android系统然后会调用Service的onStartCommand()方法并传入这个Intent对象。

比如,一个Activity可以通过明确指明调用的服务来调用前面创建的HelloService:

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

startService() 调用后立即返回,Android系统调用Service的onStartCommand(),如果这个Service之前没有运行,系统还将先调用Service的onCreate()方法,然后再调用onStartCommand()。

如果Service没有提供绑定支持,那么使用startService()是唯一可以启动Service的方法。然而,如果你需要Service返回一个结果,那么客户端可以通过创建一个用于广播的延迟Intent(PendingIntent)然后通过Intent发送请求到Service。Service可以利用这个广播(Broadcast)返回结果。

多个启动Service请求将导致多次调用Service的onStartCommand()方法。然而只要一个stopSelf或stopService来停止一个Service的运行。

停止Service

一个“Started”的Service必须管理自己的生命周期,也就是说,除非系统资源不足,Android系统不终止或停止一个Service。因此Service必须调用stopSelf () 方法来终止自身的运行,或者其它部件可以通过stopService () 方法来中止一个Service的运行。

一旦Service被请求终止,系统将尽快销毁这个Service。

但是,如果你的Service需要在onStartCommand()并行处理多个请求,那么你不应再处理完一个请求后就停止Service的运行,因为你可能还会接受到新的请求(在第一个请求处理完就结束则会终止第二个请求的执行)。为避免这种情况,你可以使用带参数的stopSelf(int) 来确保终止Service的请求总是对应于最近的请求。也就是说,在调用stopSelf(int) 时,你通过传入请求的Id (传给onStartCommand 方法的 startId )来终止对应的请求处理。那么如果Service在调用stopSelf (int) 前接受到一个新的请求,那么Id将不会匹配,因此Service也就不会结束。

创建一个支持“绑定”的Service

一个支持“绑定”的Service是指运行其它应用程序之间通过调用bindService() 来绑定到它的Service。支持“绑定”的Service在设计时通常不允许直接使用startService() 来启动它。

在Activity或其它组件需要和一个Service发生交互时,你应该创建一个“绑定”的Service,在这个Service中你可以通过进程间通信接口(IPC)来提供可供其它应用程序组件使用的功能接口。

为了创建一个支持“绑定”的Service,你需要实现onBind() 回调函数并返回一个IBind接口对象,这个对象提供了其它部分可以访问这个Service的服务接口。其它应用程序组件然后可以通过bindService () 方法获得Service的服务接口对象,然后使用这个对象的方法来调用服务。通常“绑定”的Service的运行周期和绑定它的其它应用程序组件的生命周期是一样的。因此如果这个Service不再有应用程序组件与之绑定,Android系统会自动销毁这个Service,而你自己无需停止这个Service。

为了创建一个支持“绑定”的Service所需做的第一件事是定义可供客户端调用的服务接口。这个接口必须为一个IBinder接口,并且你的Service必须通过onBind () 返回这个接口对象。一旦客户端获得这个IBinder接口,就可以通过这个接口对象来使用服务。

多个客户端可以同时绑定到同一个Service,当一个客服端使用好所需的服务后,调用onbindService() 来解除与Service之间的绑定关系。当一个Service没有和它绑定的客户端后,Android系统销毁这个Service。

给用户发送通知

Service通常是在后台运行,它可以通过Toast 通知或是状态条通知来提醒用户发生了某种事件。

一个Toast通知为覆盖在当前屏幕上短时间显示的消息,而状态条通知可以在状态条以图标和文字的方法显示,用户可以选择是否查阅这个通知并作出处理(比如启动一个Activity)。

一般来说,使用状态条通知是在某个后台工作完成后(比如文件下载完毕)通知用户的最好方法。用户可以在扩展后的通知窗口选择某个通知,然后可以点击是否启动一个Activity(比如查看下载好的文件)

在前台运行Service

通常Service在后台运行,但有时某些Service是用户明确知道在运行,即使在系统资源不足时,也不该做为销毁的候选Service,这种Service可以设置成在前台运行,在前台运行的Service必须在状态条显示通知,除非Service停止或者转入后台,这种通知不可以被忽视。

比如,如果一个音乐播放器使用Service来播放,这个Service应该被放在前台运行,因为用户很清楚的知道音乐在播放,而在状态条显示的通知理当显示当前播放的乐曲并且允许用户启动一个Activity来操作这个音乐播放器。

要把一个Service放在前台运行,可以调用startForeground()。这个方法接受两个参数:一个整数来唯一标识一个通知,和显示在状态条上的通知对象。

例如:
要使一个Service推出前台运行,调用stopForeground(). 这个方法接受一个boolean参数,指明是否同时移除状态条上的通知。 这个方法并不会停止Service的运行。但如果你停止一个在前台运行的Service,那么会同时移除状态条的通知。

1
2
3
4
5
6
7
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_ID, notification);

管理Service的生命周期

和Activity相比,Service的生命周期要简单很多。但你更要关注你的Service是如何创建和销毁的,这是因为Service可以在用户不知道的情况下在后台运行。

Service的生命周期,从其创建后到销毁,可以有两条不同的路径:

“Started”的Service 这个Service是由其它的应用程序组件调用startService()创建的,这个service 可以在后台无限期运行直到调用 stopSelf()或者其它组件调用stopService()来停止它。当Service停止时,系统将销毁这个Service。

支持“绑定”的Service 这种Service是在其它组件调用 bindService()绑定它时创建,客户端然后可以通过服务接口和Serivce通信。客户端可以调用 unbindService () 解除与Service的绑定。多个客户端可以同时绑定同一Service,当一个Service没有客户端和它绑定时,系统则销毁这个Service。

这两条路径并不是完全分开的,也就是说,你可以去绑定一个已经是“Started”状态的Service。比如,一个通过媒体播放的Service可能通过指明需要播放音乐的Intent然后调用startService() 启动的。再往后,用户可能打算来操作媒体播放器,那么一个Activity可以调用 bindServive()来绑定这个Service。在这种情况下,stopSelf()或stopSelf()并不真正停止Service直到所有的客户端都解除与Service的绑定。

实现生命周期回调函数

和Activity类似,Service也提供了一些回调函数接口允许你重载这些方法来监视Service状态的变化并添加合适的处理,下面代码给出一个Service生命周期回调函数实现的框架:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
    }
}

和Activty不同的是,Service的生命周期回调函数没有必要调用基类的对于的方法。

Servcie的生命周期

通过实现这些回调函数,你可以监视Service生命周期中两个嵌套的循环:

· 整体生命周期
指Service在onCreate()和onDestroy()之间。和Activity类似,Service可以在onCreate () 进行一些初始化工作,而在onDestroy () 中释放资源。比如,一个音乐播放器可以在onCreate() 创建用来播放音乐的线程,而在onDestroy() 停止这个线程。

· 活动生命周期
Service 在 onStartCommand() 或 onBind() 后开始活动,每个方法分别处理来自 startService和 bindService() 发过来请求 Intent。如果是“Started”的Service,那么它活动的生命周期和Service的整个生命周期是一致的。如果是“绑定”的Service,那么它的活动生命周期终止与unbind()。

总结:

  1. Service生命周期
    1)、Service生命周期只有onCreate, onStart和onDestroy,没有onResume, onPause和onStop 。 如果你在onCreate或onStart做一些很耗时间的事情,最好启动一个线程来完成,因为如果Service是跑在主线程中的,会影响到你的UI操作或者阻塞主线程中的其他事情。
    2)、Android系统会尽量保持使用Service的进程尽可能长(Service被启动或者有客户端绑定到Service)。当系统内存变低,系统需要kill现存的进程时,Service的hosting进程的优先级将会在下列的可能中保持更高
    3)、大多数时间你的Service是运行的,但在严重的内存压力下它也可能被系统kill。如果是这样,系统会在稍后尝试重新启动这个Service 。

  2. Service调用
    (1)Context.startService():Service会经历 onCreate -> onStart(如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果Service已经运行, 则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次 ); stopService的时候直接 onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动 起来后可以通过stopService关闭Service。 注意,多次调用Context.startservice()不会嵌套(即使会有相应的onStart()方法被调用),所以无论同一个服务被启动了多少 次,一旦调用Context.stopService()或者stopSelf(),他都会被停止。补充说明:传递给startService()的 Intent对象会传递给onStart()方法。调用顺序为:onCreate --> onStart(可多次调用) --> onDestroy。
    (2)Context.bindService():Service会经历onCreate() -> onBind(),onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操 作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind -> onDestroyed相应退出,所谓绑定在一起就共存亡了 。
    补充说明:传递给bindService()的Intent对象会传递给onBind(),传递给unbindService()的Intent对象会传递给onUnbind()方法。 调用顺序为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
    (3)注意事项:在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他 onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。还有一点,目前我没有遇到过需要 startService和bindService交互使用的情况(我认为不会有这种需求),所以不必去考虑交互的问题,待遇到时再考虑不迟。
    (4)BroadcastReceiver只能通过startService启动Service , 因 为广播本身生命周期很短,bind的话没有意义

  3. 与 Service 通信并且让它持续运行
    如果我们想保持和 Service 的通信,又不想让 Service 随着 Activity 退出而退出呢?你可以先 startService() 然后再 bindService() 。当你不需要绑定的时候就执行 unbindService() 方法,执行这个方法只会触发 Service 的 onUnbind() 而不会把这个 Service 销毁。这样就可以既保持和 Service 的通信,也不会随着 Activity 销毁而销毁了。

  4. 提高 Service 优先级
    Android 系统对于内存管理有自己的一套方法,为了保障系统有序稳定的运信,系统内部会自动分配,控制程序的内存使用。当系统觉得当前的资源非常有限的时候,为了保 证一些优先级高的程序能运行,就会杀掉一些他认为不重要的程序或者服务来释放内存。这样就能保证真正对用户有用的程序仍然再运行。如果你的 Service 碰上了这种情况,多半会先被杀掉。但如果你增加 Service 的优先级就能让他多留一会,我们可以用 setForeground(true) 来设置 Service 的优先级。
    为什么是 foreground ? 默认启动的 Service 是被标记为 background,当前运行的 Activity 一般被标记为 foreground,也就是说你给 Service 设置了 foreground 那么他就和正在运行的 Activity 类似优先级得到了一定的提高。当让这并不能保证你得 Service 永远不被杀掉,只是提高了他的优先级。

  5. Service与Activity的生命周期比较
    Android Service生命周期与Activity生命周期是相似的,但是也存在一些细节上也存在着重要的不同:

    1).onCreate和onStart是不同的
    通过从客户端调用Context.startService(Intent)方法我们可以启动一个服务。如果这个服务还没有运行,Android将启动它并且在onCreate方法之后调用它的onStart方法。如果这个服务已经在运行,那么它的onStart方法将被新的Intent再次调用。所以对于单个运行的Service它的onStart方法被反复调用是完全可能的并且是很正常的。

    2).onResume、onPause以及onStop是不需要的
    回调一个服务通常是没有用户界面的,所以我们也就不需要onPause、onResume或者onStop方法了。无论何时一个运行中的Service它总是在后台运行。

    3)onBind
    如果一个客户端需要持久的连接到一个服务,那么他可以调用Context.bindService方法。如果这个服务没有运行方法将通过调用onCreate方法去创建这个服务但并不调用onStart方法来启动它。相反,onBind方法将被客户端的Intent调用,并且它返回一个IBind对象以便客户端稍后可以调用这个服务。同一服务被客户端同时启动和绑定是很正常的。

    4)onDestroy
    与Activity一样,当一个服务被结束是onDestroy方法将会被调用。当没有客户端启动或绑定到一个服务时Android将终结这个服务。与很多Activity时的情况一样,当内存很低的时候Android也可能会终结一个服务。如果这种情况发生,Android也可能在内存够用的时候尝试启动被终止的服务,所以你的服务必须为重启持久保存信息,并且最好在onStart方法内来做。


原文:http://my.eoe.cn/william_sim/archive/14732.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值