Android Service

来源:互联网 发布:用友nc数据备份 编辑:程序博客网 时间:2024/05/16 06:57

Service主要有两种形式:Started和Bound,但你也可以同时使用两种方式,因此你的服务可以started,也可以bind(只要你的service实现了抽象方法onStartCommand和onBind);Started类型的服务需要通过startService方法来调用,而Bound类服务则调用bindService方法。

要注意的是服务本身并不会创建自己的线程(也就是在主线程),因此若耗CPU,则必须在service里面单独创建一个线程来处理。

基础

要创建服务就得继承Service类,应该实现的最重要的回调方法有:onStartCommand、onCreate、onDestroy和onBind。如果组件通过调用startService来启动服务,则能够服务必须自己调用stopSelf方法或者其他组件调用stopService方法来结束服务,否则它会持续运行;如果组件是通过bindService启动的服务,service只会在自己bind它的时候才会启动,一旦所有clients unbound了它,系统就会自动销毁service。

在Manifest里声明service

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

由于默认服务是公开的,如果想设置为私有,则需把属性android:exported设为false。

创建Started Service

一个Started service是由其他组件通过调用startService(此方法调用onStartCommand)来启动的服务;传统上说,你可以继承Service(所有服务的基类,只要注意得为子类创建自己的线程就行)或IntentService(这是一个使用worker thread的service子类,是不同步处理多个请求任务的好选择,你只需做的就是实现onHandleIntent方法)来创建一个Started 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 workerthread 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) {              }          }      }  }}


继承Service类

public class HelloService extends Service {  private Looper mServiceLooper;  private ServiceHandler mServiceHandler;  // Handler thatreceives 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 afile.          // 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'tstop          // the service in the middle of handling another job          stopSelf(msg.arg1);      }  }  @Override  public void onCreate() {    // Start up thethread running the service.  Note that we create a    // separatethread because the service normally runs in the process's    // main thread, whichwe don't want to block.  We also make it    // backgroundpriority so CPU-intensive work will not disrupt our UI.    HandlerThread thread = new HandlerThread("ServiceStartArguments",            Process.THREAD_PRIORITY_BACKGROUND);    thread.start();        // Get theHandlerThread'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必须返回一个integer,必须是下面3个常量之一:

1)  START_NOT_STICKY

    如果在onStartCommand返回值之后,系统kill掉service,除非还有intent要deliver,否则不重建service

2)  START_STICKY

    如果在onStartCommand返回值之后,系统kill掉service,则重建service并调用onStartCommand方法,但是不deliver最后那个intent

3)  START_REDELIVER_INTENT

    如果在onStartCommand返回值之后,系统kill掉service,则重建service并把最后一个intent deliver给它

开始服务

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

上面的代码并不会返回结果,如果你想在服务启动后返回一个结果给你,启动服务的client可以创建一个PendingIntent广播(用getBroadcast方法)并deliver到启动service的那个intent里面【deliver it to the service in the Intent that starts the service】,然后服务就可以利用那个broadcast来deliver结果啦。

停止服务

Started服务必须自己管理自己的lifecycle,所以它必须自己调用stopSelf方法或者由其它组件调用stopService方法。

假如你的服务并发处理多个请求给onStartCommand,那当你处理完一个start request的时候则不应该把service停掉,因为也许你已经收到了新的一个start request。为避免这个问题,你可以使用stopSelf(int)方法来保证你停止服务的请求是基于最recent的start request。也就是说,当你调用stopSelf(int)时,你startrequest的ID传递给 your stop requestcorresponds【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 startrequest before you were able to call stopSelf(int), then the ID will not match and theservice will not stop.

创建Bound服务

Bound服务就是允许组件通过bindService绑定以创建长时间稳定连接的服务(通常不允许通过调用startService方法来启动),当你想从activity里跟service交互时,你应该创建bound服务。

为了创建bound服务,你需要实现onBind回调方法并返回一个定义了如何与service交互的IBinder接口;创建bound服务的第一步是定义client跟service交互的接口,这个接口必须是IBinder的实现,而且它必须是你的服务从onBind方法返回来的那个接口,一旦client接收了IBinder,client和service的交互便可以开始了。

当然实现bound service的方法还有更多,详见Bound Services.

发送通知给用户

一旦运行起来,服务即可通过ToastNotification或Status BarNotification发送通知给用户

在foreground运行服务

前端服务被认为是用户想知道的东西,而且当系统内存不足时不能把它看做kill的候选者,前端服务必须为状态栏提供通知。

为了请求服务在前端运行,调用setForeground方法,需要的参数有唯一标识notification的integer和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方法则使service可从前端移除,要注意的是这两个方法的API限制为5

管理service的lifecycle

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