首页 > 代码库 > Develop系列-API Guides-应用组件-Services

Develop系列-API Guides-应用组件-Services

Services

Services:可在后台长时间运行,无UI界面。

Started:

Services通过其他组件调用startService启动,能在后台一直运行,即使启动它的组件已经销毁。一般这种服务执行特定的操作而且没有返回值,比如通过网络下载或上传一个文件,一旦操作结束,服务需要停止自己。

Bound:

Service通过其他组件调用bindService绑定,提供一个CS架构的接口允许其他组件与Service交互、发消息、获取返回值、甚至跨进程通信。bound service与绑定它的组件共存亡,多个组件可以绑定一个服务,当这个服务所有绑定它的组件都解绑后,服务会被销毁。

Caution:Service在宿主进程的主线程运行,也就是说Service不会创建自己的线程,也不会运行在另一个进程(除非你指定)。这就意味着,如果Service执行一些高CPU负载或阻塞界面操作的任务时,你需要创建新的线程来运行它,以降低ANR的风险。

(使用service还是thread?如果你只是需要在与用户交互时,在主线程之外执行额外的任务,那么你需要创建一个新线程而不是Service。比如在activity在前台显示的时候播放音乐,你需要在onCreate里面创建线程,在onStart执行线程,在onStop里停止线程,当然也可以使用AsyncTask或者HandleThread来替代线程类。)

基础

创建Service的子类,覆写Service生命周期中的关键回调函数,如果有必要,提供绑定Service的机制。最重要的回调函数如下:

onStartCommand

系统在其他组件调用startService启动Service时执行,之后,Service一直在后台执行。如果你实现了这个方法,那么你有责任在Service完成其工作时通过stopSelf或stopService来停止Service。(如果只是提供绑定Service,可以不用实现这个方法)

onBind

系统在其他组件调用bindService绑定Service时执行,在这个方法的实现中,你需要返回一个IBider接口用于clients与service交互。如果你不需要绑定,可以直接返回null

onCreate

Service第一次创建时执行,在onStartCommand和onBind之前,用于执行一次性需要初始化好的数据。

onDestroy

service销毁时执行,用于清理资源,类似线程、注册监听器,receiver等。

 

系统会在低内存时强制停止service。如果service绑定在一个有用户焦点的activity,那么它很少会被销毁;如果服务定义为在前台运行的,那么它永远不会被销毁。

在manifest定义service

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

android:name是唯一必填的属性,其他可以选填。一旦你的应用发布出去了,那么android:name永远不要再变。

为了安全性,请使用显式Intent启动或绑定服务,而不是定义filiters。如果确实允许多个服务来响应,那么请务必在Intent中通过setPackage来指定报名,以降低目标服务匹配出意外值得概率。

设置android:exported为false,可以避免其他应用启动这个服务。

创建service

Service

所有服务的基类,如果你扩展这个类,那么你可能需要创建一个新的线程,因为这个服务室在app的主线程中执行,有可能会降低activity的流畅度

IntentService

Service 的子类,通过工作线程来处理所有请求,每次处理一个。如果你的service不需要同时处理多个请求,IntentService是最佳的选择。

扩展IntentService

因为大部分服务不需要同时处理多个请求(实际上是个多线程场景),IntentService是最好的推荐

IntentService工作流程如下:

  • 创建一个默认的新工作线程来执行所有分发给onStartCommand的intents
  • 创建一个工作队列来依次传递intent去执行onHandleIntent具体实现,所以不需要考虑多线程场景
  • 所有请求执行完之后,自动销毁,你不需要执行stopSelf
  • 提供默认的onBind实现:直接返回null
  • 提供onStartCommand默认实现:发送intent给工作线程执行onHandleIntent实现

实际上,你需要做的就是实现onHandleIntent,如下例子:

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

如果你需要覆写其他回调,比如onCreate、onStartCommand、onDestroy,请确保要调用父类的实现,这样IntentService才能处理工作线程的生命周期。onHandleIntent和onBind是例外。

扩展Service

如果服务需要支持多线程(而不是通过工作队列来一一处理),那么你要扩展Service来处理每一个intent。

作为对比,如下代码和上面代码功能一样。

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必须返回一个整型,这个值用来描述系统如何处理这个服务,当它被异常销毁时。

START_NOT_STICKY

如果服务执行完onStartCommand后被异常销毁,不需要重新创建服务,除非还有未处理的intents。避免服务被不必要地启动,你的应用能够很容易地重新启动未完成的工作,选择这个。

START_STICKY

如果服务执行完onStartCommand后被异常销毁,重新创建服务并执行onStartCommand,但是不会使用发给这个服务的最后一个intent,而是通过一个null intent来执行onStartCommand,除非还有未处理的intents。这种情况比较适合不执行命令,一直在后台运行或者等待任务的媒体播放。

START_REDELIVER_INTENT

如果服务执行完onStartCommand后被异常销毁,重新创建服务,用发给这个服务的最后一个intent调用onStartCommand,其他未处理的intents依次分发。这种情况适合执行的任务需要理解恢复的场景,比如下载文件。

启动服务

startService –> onStartCommand

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

startService方法立即返回。

如果service不能绑定,只能通过startService启动,而且需要发送返回值时,可以通过创建带延迟广播的PendingIntent(用getBroadcast)来启动服务,服务能用里面的广播来分发结果。

停止服务

如果服务同步地处理多个请求,那么不能在处理完一个请求直接销毁,有可能其他的请求刚发过来或者还在处理中。为了避免这种情况,你可以通过stopSelf(int)来确保关闭的服务就是刚处理完请求的,而不是其他正在处理的服务,整型参数唯一标识服务实例。

创建绑定服务

详见下一章节

发送Notifications给用户

服务一旦运行,可以通过Toast Notifications和Status Bar Notifications提醒用户。

在前台运行服务

在前台运行的服务必须提供一个状态栏的notification,来呈现运行状态,除非服务被停止或者移除,否则notification不会消失。

比如:播放音乐,在状态栏有个notification来告诉用户当前播放的歌曲,提供用户进入音乐播放器的入口

服务需要在前台运行,需要调用startForground,第一个参数是notification的唯一标示(不能为0),第一参数就是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_ID, notification);

停止在前台运行,可以调用stopForeground。

实现生命周期回调

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:不需要执行父类的实现。

 

完整的生命周期:onCreate —> onDestroy

活动的生命周期:onStartCommand/onBind —> onDestroy/onUnbind