Android学习笔记16——Service(2)

接下来我们开始学习如何在Manifest文件中定义一个Service

<span style="font-size:14px;"><manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest></span>

我们可以在Service这个元素中定义一些属性例如启动这个Service所需要的权限或者这个Service将要运行的进程。而android:name是仅仅必须的——它用来指定这个Service的类名称。一旦你发布了自己的应用,这个Service的名称就不能改变,因为这样可能影响到其他将要调用这个Service的应用。有的时候为了确保我们的app的安全,我们在启动或者绑定一个Service的时候定义一个精确的Service而不会定义这个Service的Intent Filter。另外,如果我们想要我们自己的程序运行我们的Serivce,我们可以通过定义andriod:exported = false。这样将有效的阻止其他应用程序启动这个Service,甚至于通过一个不精确的Intent的。

创建一个已经启动的Service

一个已经启动的Service就是其他的组件调用startService方法或者bindService方法启动并且调用这个Service的onStartCommond方法的Service。

当一个Service被启动的时候,它就会拥有独立于启动这个Service的组件的生命周期,并且这个Service能够独立运行在后台,即使这个组件被销毁掉。这个Service将会一直运行下去直到这个Service自己调用stopSelf方法,或者另一个组件调用stopService方法停止这个Service。

一个应用程序的组件例如一个Activity能够通过通过startService方法来开启这个Service,并且向这个Service传递一个Intent并且包含一些这个Service要使用的数据,而这个Service将会在onStartCommond方法中接受到这个Intent。

在这里我们可以通过继承Service和IntentService类来定义一个自己的Service。

Service:这个是所有Service的父类。当我们使用这个Service的时候,我们需要自己开启开启一个新的线程去完成这个Service要做的工作。因为这个Service默认的使用这个应用程序的主线程,这样将要减慢应用程序的速度。

IntentService:这是一个Service的子类,它用一个工作线程去完成所有请求的任务,但是一次只能执行一个请求。这样,这个IntentService就成为了我们最好的选择,如果我们的Service不要求多线程工作的话。我们所需要做的是实现onHandleIntent方法,在这个方法中我们接受到每个请求的Intent,这样就能够在后台工作。

继承IntentService类

因为大多数被启动的Service不需要同时进行多个请求(这也是一种非常危险的多线程方案),如此一来,继承IntentService类来定义自己的Service可能成为一种最好的方式。

IntentService做了以下操作:

1、创建一个默认的工作线程用来执行所有的发送给onStartCommond方法的Intent,这个线程是独立于这个应用的主线程的。

2、创建一个工作队列,这个队列一次只能传递一个Intent给onHandleIntent方法的实现,因此我们不需要担心多线程的问题。

3、当所有的请求的Intent进行完成以后,这个Service自动停止,我们不需要调用stopSelf方法来停止这个Service。

4、提供onBind的默认实现,返回一个NULL。

5、提供onStartCommond方法的默认实现,发送Intent到工作队列,然后传递给onHandleIntent方法的默认实现。

<span style="font-size:14px;">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) {
              }
          }
      }
  }
}</span>
有以上代码我们可以看出我们需要做的仅是:提供一个构造方法并且实现onHandleIntent方法。

但是如果我们也想要实现其他方法,我们必须记得首先调用他们父类的实现,以至于IntentService能够正确的操作这个工作线程的生命周期。

<span style="font-size:14px;">@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);
}</span>

除了onHandleIntent方法以外,我们不需要调用父类实现的唯一的方法是onBind()方法。

继承Service类

正如上面的例子一样,继承IntentService将会事我们自定义的Service更加简单。然而,如果我们希望我们的Service能够表现多线程操作,而不是通过工作队列,那么我们需要继承Service来操作每一个Intent。

作为比较,下面的代码实例是一个继承了Service类并且进行和IntentService相同操作,对于每一个请求都用一个工作线程去完成,一次仅仅进行一个请求。

<span style="font-size:14px;">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();
  }
}</span>

真如我们看到的,它做了比IntentService更多的工作才能完成相同的任务。

然而,正是因为我们操作了每一个请求,这样我们也就可以同时进行多个请求的操作。如果我们想到达到这个目的,我们可以为每一个Intent启动一个新的线程来完成不同的工作。

注意onStartCommond方法必须返回一个int类型的数值,而这个数值描述了当系统杀死这个Service时的时候,系统将要怎么进行这个Service。返回的常量必须是以下几种数值:

START_NOT_STICKY:这个数值代表如果系统杀死了这个Service,这个Service将要不会重新创建,除非有一个PendingIntent被发送。这是最安全的方式,避免了当我们的Service在不需要或者仅仅需要重新启动未完成的任务的时候运行。

START_STICKY:这个数值代表,当系统杀死这个Service的时候,系统会重新创建这个Service,并且调用onStartCommond方法,但是不会重新发送最后一个Intent。相反,系统用一个null的Intent调用onStartCommond方法,除非有一些pendingIntent来开启这个Service,在这种情况下这些Service被发送。这种方式适合于一个音乐播放器,不执行命令只是在后台运行并且等待着一个工作。

START_REDELIVER_INTENT:这个数值代表如果系统杀死了这个Service,系统会重新创建这个Serivice,并且用发送给这个Service的最后一个Intent来调用onStartCommond方法。任何pendingIntent被依次发送。这适合于需要立即恢复的工作,例如文件下载。






发布了43 篇原创文章 · 获赞 25 · 访问量 7万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章