首页 > 代码库 > Service(1)

Service(1)

服务是一个应用组件,能够在后运行耗时的操作,不提供一个用户界面。(由于不提供界面,所以能够耗时运行,和活动最大的不同)。还有一个应用组件能够启动一个服务,服务会继续在后台运行及时用户切换到还有一个应用(和活动不一样,那么生命周期就有不同了)。此外,一个组件能够绑定一个服务和他进行交互甚至运行进程间通信(interprocess communication (IPC))。举例,一个服务可能处理网络事务,播放音乐,运行文件或者和一个content provider交互,全部都是在后台。


    一个服务本质上接收两种格式:
Started
    当一个组件(比方活动)调用startService的时候 ,一个服务启动。

一旦启动,一个服务能够在后台无限期的执行。即使启动他的组件被销毁了。通常,一个启动的服务执行一个单一的操作,不给调用者返回一个结果。举例,服务可能通过网络下载或者更新文件。

当操作完毕,服务应该自己停止自己。
Bound
当一个应用组件调用bindService绑定到他上面服务被bound。一个bound的服务,提供一个clientserver界面。同意组件和这个服务交互,发送请求。得到结果,甚至通过进程间通信实现这些。

一个bound服务,仅仅有在还有一个组件绑定到他上面才会运行。多个组件能够立即绑定到这个服务,可是当他们都解绑了,服务被销毁。
尽管这个文件通常独立的讨论这两种服务。我们的服务能够以这两种方式工作。

能够被启动(无限期运行)并且同意绑定。主要就看我们是不是实现一对回调方法:onStartCommand同意组件启动他,onBind同意绑定。
不管我们的程序是否启动,bound,或者全部。不论什么应用组件都能够使用这个服务(即使从一个分开的程序)。不论什么组件也能够以相同的方式使用活动,通过intent启动他。然后。我们能够声明服务为私有的。在manifest文件里。阻止其它程序訪问他。

在下文会讲吧。
小心:一个服务在他的宿主进程的主线程中执行,服务不创建他自己的线程。不在一个独立的进程中执行(除非我们另外指定)。这就意味着。假设我们的服务去做不论什么CPU集中的工作或者堵塞动作(比方mp3播放或网络工作),我们应该在服务中新建一个线程做这些工作。

通过使用独立的线程。我们能够减少ANR错误的风险,而且我们的主线程能够一直保持献身于用户交互使用活动。
The Basics
    要创建一个服务,我们必须创建一个Service的子类(或者一个应经存在的子类)。在我们的实现中,假设有须要,重写一些回调方法处理服务生命周期的主要方便和为组件提供一个绑定到服务的机制。最重要的能够重写的回调方法例如以下:
onStartCommand()
  系统调用这种方法当还有一个组件,比方活动。通过调用startService要求这个服务启动。一旦方法执行。服务被启动。能够在后台无限期执行。假设我们实现这种方法,当服务的工作完毕后是我们的责任去停止服务。通过调用 stopSelf() 或 stopService()(假设只想提供绑定,不须要实现这种方法,非常明显啊,这是start用的)
onBind()
   系统调用这种方法当还有一个组件调用BingService希望绑定到这个服务上(比方运行RPC)。

在方法的实现中,我们必须提供一个接口。client用来和服务交流。通过返回一个LBinder。

必须总是实现这种方法,假设不同意绑定。应该返回null。
onCreate()
    当服务第一次创建的时候系统调用他,执行一次性的设置程序(before it calls either onStartCommand() or onBind() 在??前)。

假设服务应经执行了,这种方法不会调用。


onDestroy()
   系统调用这种方法当服务不在被使用而且将要被销毁。我们的服务应该实现这种方法去清理不论什么资源,比方线程,注冊的监听器,接收器等。这是服务接收的最后一个调用的方法。


假设一个组件通过调用startService启动服务(导致一个onStartCommand调用,然后这个服务保持执行,直到通过stopSelf停止或者还有一个组件调用stopService停止他。
假设一个组件调用bindService去创建一个服务(onStartCommand不会调用)。然后这个服务仅仅有在组件绑定上才运行。一旦服务和所以的client解除绑定,系统应该销毁他。
安卓系统会强制停止一个服务仅仅有当内存非常低,必须为用户操作的活动恢复系统资源的时候。假设服务绑定到用户聚焦的活动上。他不太可能比杀死。假设服务被声明run in the foreground (一会讲),他差点儿不会被杀死。

否则,一个服务被启动。长时间运行,系统会减少他在后台任务的位置随着时间推移。服务会变得非常easy被杀死,假设我们的服务启动。我们必须非常优雅的设计去处理系统的重新启动。假设系统杀死我们的服务。一旦资源可用会重新启动服务(尽管这个也依靠我们从onStartCommand返回的值,一会讲)。
For more information about when the system might destroy a service, see the Processes and Threading document.


Should you use a service or a thread?
A service is simply a component that can run in the background even when the user is not interacting with your application. Thus, you should create a service only if that is what you need.
一个服务不过一个能够后天执行的组件,即使用户不和我们的应用交互。这样,我们应再唯独须要的时候才创建一个服务。


假设须要在main线程之外运行任务,可是仅仅有在用户和程序交互的时候,我们可能仅仅创建一个新线程而不是一个服务。举例,想播放音乐。可是仅仅有活动运行的时候才愿意,能够在onCreate中创建一个线程,在onStart中開始运行。然后在onStop停止。
也能够考虑使用 AsyncTask or HandlerThread,取代传统线程。See the Processes and Threading document for more information about threads.
记住。假设使用一个服务,他仍然默认在主线程中执行,所以假设执行密集和堵塞操作。应该仍然创建一个新的线程。
以下開始讲,怎样创建每种类型的服务和从其它应用组件怎样使用它。
Declaring a service in the manifest
和活动(其它组件一样)。必须在应用的manifest文件里定义所以的服务。


在<application>元素中加入一个<service>元素作为子元素。例如以下:
<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>


能够在<service>元素中包括其它元素定义属性,不日启动这个服务的权限和这个服务应该执行的进程。Android:name 是唯一必须的属性,指定了服务的类名。

一旦公布应用,不应该改变这个名称。由于这样做,打破显式的意图或者绑定这个服务的代码。查看blog Things That Cannot Change) 。
为了确保app的安全。总是使用显式意图启动和绑定服务。不要给服务声明intent过滤器。
To ensure your app is secure, always use an explicit intent when starting or binding your Service and do not declare intent filters for the service. If it‘s critical that you allow for some amount of ambiguity as to which service starts, you can supply intent filters for your services and exclude the component name from the Intent, but you then must set the package for the intent with setPackage(), which provides sufficient disambiguation for the target service.
此外,设置 android:exported 属性为false阻止其它程序启动我们的服务。

这样能够有效的阻止其它程序启动我们的服务,即使使用显式意图。(和活动非常像啊).
Creating a Started Service
一个被启动的服务是还有一个组件通过调用startService启动的,导致服务调用他的onStartCommand方法。


当一个服务是被启动。它的生命周期独立于启动他的组件,服务能够在后台无限的执行,及时启动他的组件被销毁了。因此,服务应该在任务完毕的时候调用stopSelf停止或者其它组件调用stopService停止。
一个应用组件,比方一个活动能够通过调用startService启动服务,传递说明这个服务的和包括这个服务使用的信息的intent。

服务在onStartCommand方法中接收这个Intent。
打个例如,如果一个活动须要保存一些数据到线上的数据库。活动能够启动一个同伴服务,通过传递一个inent给startService传送给服务须要保存的数据。服务在onStartCommand接收这个Intent,连接网络。运行数据库事务。当事务结束,服务停止自己。然后被销毁。
小心:默认,一个服务在和主线程所在的进程中运行。所以,假设服务运行集中的或者堵塞动作当用户和应用程序的活动交互。服务会减缓活动表现。为了避免影响应用的表现。应该在服务中启动一个新线程。


习惯上,有两个类能够实现去创建一个被启动的服务:
Service
    全部服务的基础类。

当继承这个类,非常重要去创建一个新的线程去运行所以的服务操作,由于服务默认使用应用的主线程,可能会减缓其它活动的运行。


IntentService
    这是Service的一个子类。使用工作线程处理全部的启開始请求,一次一个。假设不要求服务同一时候处理多个请求。这是最好的选择。我们要做的就是实现onHandleIntent,为每个開始请求接收Intent,这样就能够做后台工作。
This is a subclass of Service that uses a worker thread to handle all start requests, one at a time. This is the best option if you don‘t require that your service handle multiple requests simultaneously. All you need to do is implement onHandleIntent(), which receives the intent for each start request so you can do the background work.
Extending the IntentService class
由于大多数的被启动的服务不须要同一时候处理多个请求(实际上多线程非常危急)。这时候应该最好使用IntentService。


IntentService做了以下的事:
The IntentService does the following:
? 创建一个默认的工作线程运行所以传递给onStartCommand的intents独立于应用的主线程(新的线程了,所以不会干扰,那还说我自己要新启线程。应该是直接Service须要)
? 创建一个工作序列,一次传递一个intent给onHandleIntent实现。所以永远不用操心多线程
? 全部的开启请求被处理完之后停止服务,所以永远不用调用stopSelf
? 提供onBind的默认实现。返回null
? 提供onStartCommand的默认实现,这种方法发送intent给工作序列。然后发送intent给onHandleIntent实现。


全部这些加起来。我们须要做的就是实现onHandleIntent。运行client提交的任务(尽管,还须要提供一个小的构造器给服务,以下会看到)
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,onDe。确定调用父类的实现,这样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实现的相同的服务。会有很多其它的代码。可是假设要同一时候处理多个開始请求是合适的。


Extending the Service class
上面展示的,使用IntentService让我们实现一个启动服务很easy。假设,然而。须要服务运行多线程(而不是处理启动请求通过一个工作序列)。然后能够继承Service类去处理每个Intent。
作为对照,以下的代码是一个Service类的实现。运行和上面IntentService一样的工作。那就是,为每个启动请求。他使用一个工作线程去运行这个任务,一次仅仅处理一个请求。
For comparison, the following example code is an implementation of the Service class that performs the exact same work as the example above using IntentService. That is, for each start request, it uses a worker thread to perform the job and processes only one request at a time.
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();
  }
}


然后。由于处理每个调用给onStartCommand,能够同一时候运行多个请求(和上面什么差别。没懂?)。这个样例没有这做,可是假设想这么做。为每个请求创建一个新线程(就是新建一个线程,上面的样例没有新建一个线程。多个线程怎么停啊,这是个问题??),然后立刻运行他们(而不是等待上一个运行完成)
    多个停止是,为每个request设置一个Id。然后假设这个ID和正在运行的不一致就不会停止,上面的样例不行啊,多个线程。多次调用这个stop。万一有一个成功呢,还须要研究。怎么停止。下文也没讲清楚啊。 
注意到,onStartCommand方法必须返回一个整数,这个整数是一个数值描写叙述系统应该怎样继续这个服务在这个事件当系统杀死他(上面调理,对于Intentservice默认的实现帮我们处理。尽管我们能够改动他)。onStartCommand的返回值必须的以下其中的一个常量:
START_NOT_STICKY
If the system kills the service after onStartCommand() returns, do not recreate the service, unless there are pending intents to deliver. This is the safest option to avoid running your service when not necessary and when your application can simply restart any unfinished jobs.
START_STICKY
If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), but do not redeliver the last intent. Instead, the system calls onStartCommand() with a null intent, unless there were pending intents to start the service, in which case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands, but running indefinitely and waiting for a job.
START_REDELIVER_INTENT
If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand() with the last intent that was delivered to the service. Any pending intents are delivered in turn. This is suitable for services that are actively performing a job that should be immediately resumed, such as downloading a file.


Stopping a service
A started service must manage its own lifecycle. That is, the system does not stop or destroy the service unless it must recover system memory and the service continues to run after onStartCommand() returns. So, the service must stop itself by calling stopSelf() or another component can stop it by calling stopService().
Once requested to stop with stopSelf() or stopService(), the system destroys the service as soon as possible.
说是这个ID是建立在最新的一个请求的。也就是说前面的请求的id和传给onStartCommand方法的ID不一致,仅仅要有新请求。id就变,会不会有開始仅仅有一个运行。然后其它等到这个运行了还没运行。不就stop了。呵呵
However, if your service handles multiple requests to onStartCommand() concurrently, then you shouldn‘t stop the service when you‘re done processing a start request, because you might have since received a new start request (stopping at the end of the first request would terminate the second one). To avoid this problem, you can use stopSelf(int) to ensure that your request to stop the service is always based on the most recent start request. That is, when you call stopSelf(int), you pass the ID of the start request (the startId delivered to onStartCommand()) to which your stop request corresponds. Then if the service received a new start request before you were able to call stopSelf(int), then the ID will not match and the service will not stop.
Caution: It‘s important that your application stops its services when it‘s done working, to avoid wasting system resources and consuming battery power. If necessary, other components can stop the service by calling stopService(). Even if you enable binding for the service, you must always stop the service yourself if it ever received a call to onStartCommand().
?
Creating a Bound Service
一个绑定服务是一个服务同意应用组件通过调用bindService绑定到他上面创建一个长期存在的关系(通常不同意组件调用startService启动他)。
当我们想和来自程序中的活动或者其它组件的服务交互或者通过进程通信暴露一些应用程序的功能给其它应用。应该创建一个绑定服务。


(1)要创建一个绑定服务,必须实现onBind方法,返回一个定义和服务通信的接口的IBinder(2)其它应用组件然后能够调用bindService(这种方法有个ServiceConnection參数,须要设置一些)方法获得这个接口,開始调用服务上的方法。
要创建一个绑定服务,第一件要做的事就是定义指定client怎样跟服务通信的接口。(一般我们的是不在服务中创建一个Binder(实现IBinder接口)的实例)。这个接口必须是一个IBinder的实现,同一时候是服务必须在onBind回调方法返回的。一旦client收到这个IBinder。能够通过那个接口和服务交互。
多个client能够同一时候绑定到一个服务。当一个client和服务运行完交互,调用unBindService去解绑。一旦没有client绑定到服务上,系统销毁这个服务。
有多种方式实现一个绑定服务,并且实现比启动的服务更复杂。所以这个绑定服务在独立的绑定服务文档讨论。


?
Managing the Lifecycle of a Service
服务的生命周期和活动非常像。

然而,更重要的是,我们应该更关注我们的服务怎样创建和销毁。由于一个服务能够在用户不知道情况下在后台执行。
服务的生命周期重创建到销毁有这两个路劲:
? A started service 
还有一个组件调用startService()启动这个服务.服务然后在后台无限期执行,必须调用stopSelf停止自己。

还有一程序也能够调用stopService停止。当服务停止,系统销毁他。 
? A bound service 
当还有一个组件(一个client)调用bindService的时候,服务被创建。client然后通过IBinder接口和服务通信。多个client能够绑定到同一个服务。当他们所有解绑,系统销毁这个服务(服务不须要自己停止)。
这两个路径不是全然分离的。

那就是。能够绑定到一个已经由startSercie启动的服务。

举例,一个后台音乐服务能够通过调用statService用一个确认要播放的音乐Intent启动。然后,可能当用户想运行一些控制在这个播放器或者得到当前歌曲的信息。一个活动通过调用bindService绑定到服务上。

在这种样例,stopService() or stopSelf() 不能停止服务直到全部的client解绑。(全部client解绑,应该也不停止服务吧。除非调用这个两个方法) 
Implementing the lifecycle callbacks
和活动非常像。一个服务有生命周期回调方法我们能够实现去监听服务的状态改变,在适合的实际运行工作。以下的骨架服务展示了每个生命周期方法。
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
    }
}
Note:不像活动的生命周期回来方法,不用调用父类的这些方法的实现。 
 
Figure 2. The service lifecycle. The diagram on the left shows the lifecycle when the service is created with startService() and the diagram on the right shows the lifecycle when the service is created with bindService().
通过实现写方法,能够监听两个嵌套的服务生命周期循环。


? 服务的整个生命周期发生在onCreate被调用和onDestroy返回之间。

项一个活动。服务在onCreate进行初始化设置,在onDestroy中释放全部资源。举例。一个音乐播放服务能够在onCreate中创建音乐播放的线程。然后在onDestroy中停止这个线程。
能够看到。onCreate()和 onDestroy()方法被全部服务调用,不管他们的由startService() 还是bindService()创建。
? 服务的活跃生命时间 从onStartCommand或者onBind開始。每一个方法分别处理来自startService或者bindService传递的intent
假设服务是被启动,活跃生命周期随着整个生命周期结束而结束(服务仍然是活跃的,甚至在onStartCommand返回之后)。假设服务是绑定的,活跃生命时间随着onUnbind返回结束。


Note:尽管一个被启动的服务由stopSelf() or stopService()停止, 服务没有一个回调方法(没有onStop回调)。所以。除非服务绑定到一个client。否则当服务停止系统销毁他。onDestroy是被接收唯一的回调方法。
    上图阐明了服务的典型的回调方法。

尽管该图分离了由startService和bindService创建的服务,在心中铭记。不论什么服务。不管怎样启动,能够潜在的同意client绑定他。

所以,一个最初有onStartCommand方法(通过client调用startService)启动的服务。仍然能够接受一个onBind(当一个client调用bindService) bind 能够被启动吗,应该是不能够吧。
查看Bound Service很多其它。


?
?





Service(1)