Android Service 详解三:从类Service派生service

从类Service派生

  如你在上节所见,使用类IntentService使得你实现一个"开始的"service非常容易.然而,如果你需要你的service以多线程方式执行(而不是使用工作队列),那么你需要从类Service派生来处理每个intent



  相比之下,下面的例子从类Service派生并实现了与上面使用IntentService例子完全相同的工作.也就是在一个线程中序列化的处理每个"开始"请求.

  1. <SPAN style="FONT-SIZE: 18px">public class HelloService extends Service {  
  2.   private Looper mServiceLooper;  
  3.   private ServiceHandler mServiceHandler;  
  4.   
  5.   // 处理从线程收到的消息们   
  6.   private final class ServiceHandler extends Handler {  
  7.       public ServiceHandler(Looper looper) {  
  8.           super(looper);  
  9.       }  
  10.       @Override  
  11.       public void handleMessage(Message msg) {  
  12.           // 通常我们在这里做一些工作比如下载一个文件   
  13.           // 在我们的例子中,仅仅是睡5秒钟.   
  14.           long endTime = System.currentTimeMillis() + 5*1000;  
  15.           while (System.currentTimeMillis() < endTime) {  
  16.               synchronized (this) {  
  17.                   try {  
  18.                       wait(endTime - System.currentTimeMillis());  
  19.                   } catch (Exception e) {  
  20.                   }  
  21.               }  
  22.           }  
  23.           // 使用startId停止服务,从而使我们不会在处理   
  24.           // 另一个工作的中间停止service   
  25.           stopSelf(msg.arg1);  
  26.       }  
  27.   }  
  28.   
  29.   @Override  
  30.   public void onCreate() {  
  31.     // 启动运行service的线程.注意我创建了一个   
  32.     // 分离的线程,因为service通常都是在进程的   
  33.     // 主线程中运行,但我们不想让主线程阻塞.我们还把新线程   
  34.     // 搞成后台级的优先级,从而减少对UI线程(主线程的影响).   
  35.     HandlerThread thread = new HandlerThread("ServiceStartArguments",  
  36.             Process.THREAD_PRIORITY_BACKGROUND);  
  37.     thread.start();  
  38.       
  39.     // Get the HandlerThread's Looper and use it for our Handler    
  40.     mServiceLooper = thread.getLooper();  
  41.     mServiceHandler = new ServiceHandler(mServiceLooper);  
  42.   }  
  43.   
  44.   @Override  
  45.   public int onStartCommand(Intent intent, int flags, int startId) {  
  46.       Toast.makeText(this"service starting", Toast.LENGTH_SHORT).show();  
  47.   
  48.       // 对于每个开始请求,发送一消息来开始一次工作,并且把   
  49.       // start ID也传过去,所以当完成一个工作时,我们才知道要停止哪个请求.   
  50.       Message msg = mServiceHandler.obtainMessage();  
  51.       msg.arg1 = startId;  
  52.       mServiceHandler.sendMessage(msg);  
  53.         
  54.       // 如果我们在这里返回后被被杀死了,重启之.   
  55.       return START_STICKY;  
  56.   }  
  57.   
  58.   @Override  
  59.   public IBinder onBind(Intent intent) {  
  60.       // We don't provide binding, so return null   
  61.       return null;  
  62.   }  
  63.     
  64.   @Override  
  65.   public void onDestroy() {  
  66.     Toast.makeText(this"service done", Toast.LENGTH_SHORT).show();   
  67.   }  
  68. }  
  69. </SPAN>  
<span style="font-size:18px;">public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;

  // 处理从线程收到的消息们
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // 通常我们在这里做一些工作比如下载一个文件
          // 在我们的例子中,仅仅是睡5秒钟.
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
          // 使用startId停止服务,从而使我们不会在处理
          // 另一个工作的中间停止service
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // 启动运行service的线程.注意我创建了一个
    // 分离的线程,因为service通常都是在进程的
    // 主线程中运行,但我们不想让主线程阻塞.我们还把新线程
    // 搞成后台级的优先级,从而减少对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();

      // 对于每个开始请求,发送一消息来开始一次工作,并且把
      // start ID也传过去,所以当完成一个工作时,我们才知道要停止哪个请求.
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);
      
      // 如果我们在这里返回后被被杀死了,重启之.
      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时多一些.



  然而,因为你自己处理每次对onStartCommand()的调用,你可以同时执行多个请求.这个例子并没有那样做,但是如果那是你所需要的,那么你可以为每个请求创建一个新的线程并且立即运行它们(而不是等待上一个请求完成)



  注意方法onStartCommand()必须返回一个整数.这个整数描述了在系统杀死它的事件中系统如何继续这个服务(如前面所述,IntentService的默认实现为你处理这些,当然你也能够去改写它)onStartCommand()也返回值必须是下面常量之一:

  • START_NOT_STICKY

      如果系统在onStartCommand()返回后杀死了服务,不要重新创建这个service,除非还有挂起的intent需要被传送.这是避免在不必要时运行你的service和当你的应用可以简单重启任何未竟的工作时的最佳选择.

  • START_STICKY

      如果系统在onStartCommand()返回后杀死了这个service,会重新创建这个service并且调用onStartCommand(),但是不再重新发送上次最后一个intent,而是使用一个nullintent调用onStartCommand(),除非有一些挂起的intent,在此情况下,这些挂起的intent被派送.这适合于媒体播放器(or或相似也的服务),它不执行命令,但是无限期的运行并等待一个工作.

  • START_REDELIVER_INTENT

      如果系统在onStartCommand()返回后杀死了service,重新创建这个service并且使用上次最后一个intent调用onStartCommand().任何挂起的intent都顺序地被派送.这适合于活跃地执行一个工作并且应被立即恢复的服务,比如下载一个文件.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值