`
coolxing
  • 浏览: 874168 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
9a45b66b-c585-3a35-8680-2e466b75e3f8
Java Concurre...
浏览量:97281
社区版块
存档分类
最新评论

android笔记--处理started service的多次启动请求

阅读更多

[coolxing按: 转载请注明作者和出处, 如有谬误, 欢迎在评论中指正.]

 

所谓的started service, 是我对以startService()方法启动的service的叫法. Service运行在所在进程的main thread. 启动一个service, 不会自动为该service创建新的thread. 这意味着开发者通常需要为service开启新的线程, 以执行耗时或者阻塞操作否则可能导致ANR错误的发生. 既然如此, 为何不在activity中直接开启新的线程执行耗时操作或者阻塞操作呢? 原因在于一个包含正在运行的service的进程具有更安全的进程优先级--它的进程优先级至少是service process, activity处于后台运行时它的进程优先级为background process, 在系统内存不足时, 处于后台运行的activity更有可能被系统杀死. 关于进程优先级, 在我的另一篇博文中有过介绍http://coolxing.iteye.com/blog/1279170.

如果没有调用stopService()方法或者stopSelf()方法, 就算onStartCommand()方法执行完成, service仍然处于active状态, onStartCommand()方法返回后, 系统可能处于内存不足的缘故摧毁这个service, 如果发生这种情形, 那么系统将尽快重建这个service, onStartCommand()方法的返回值用来定义系统该如何重建service, 返回值的可以是以下3int值中的一个:

  • START_NOT_STICKY, 表明不要重建service. 这可以避免在非必要的情况下浪费系统的资源.
  • START_STICKY, 表明需要重建service, 并在重建service之后调用onStartCommand()方法, 传递给该方法的intentnull.
  • START_REDELIVER_INTENT, 表明需要重建service, 并在重建service之后调用onStartCommand()方法, 传递给该方法的intentservice被摧毁之前接收到的最后一个intent.     

service第一次被启动时会调用onCreate()方法, 然后再调用onStartCommand()方法. 在该service的生命周期内, 如果再次启动这个service, 就会直接调用onStartCommand()方法了.

onStartCommand(Intent intent, int flags, int startid)方法的第一个参数intent就是用于启动该serviceintent, 第二个参数flags的值通常为0, 第三个参数startid标识此次启动请求, 通常用于stopSelf(int)方法.

通常情况下, started service应该使用单线程处理多个启动请求, 此时继承IntentService是一个更好的选择, 当然也可以继承Service, 只是会导致更多的代码. 不过如果started service需要并发处理多个启动请求, 那么只能继承Service.

继承Service--以单线程的方式处理多个启动请求

         单线程方式处理多个启动请求是大多数时候的选择, 因为该方式可以有效的处理所有请求, 却有着不需要考虑线程安全的优势. 下面的例子使用了HandlerThreadHandler类构建了单线程模型, 关于Handler, Looper, Message等线程相关的概念, 请参考我的另一篇博文http://coolxing.iteye.com/blog/1208371.

public class SingleService extends Service {
   private static final int NEW_INTENT_COMMING = 0;
   private Handler handler;
 
   private final class WorkThreadHanlder extends Handler {
      // 使用指定Looper创建Handler
      public WorkThreadHanlder(Looper looper) {
         super(looper);
      }
 
      @Override
      public void handleMessage(Message msg) {
         if (msg.what == NEW_INTENT_COMMING) {
            Log.d("SingleService", Thread.currentThread().getName());
            try {
                Thread.sleep(5 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // arg1中存储的是onStartCommand()方法的startId参数
            stopSelf(msg.arg1);
         }
      }
   }
 
   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
      Message msg = handler.obtainMessage();
      msg.arg1 = startId;
      msg.what = NEW_INTENT_COMMING;
      msg.sendToTarget();
      return START_STICKY;
   }
 
   @Override
   public void onCreate() {
      super.onCreate();
      HandlerThread thread = new HandlerThread("work thread",
            Process.THREAD_PRIORITY_BACKGROUND);
      // thread启动之后才能调用getLooper()方法获取thread中的Looper对象
      thread.start();
      // 使用子线程的Looper创建handler, 该handler绑定在子线程的消息队列上
      handler = new WorkThreadHanlder(thread.getLooper());
   }
 
   @Override
   public IBinder onBind(Intent intent) {
      return null;
   }
}

继承IntentService--以单线程的方式处理多个启动请求

         从上面的例子可以看到, Service中构建单线程模型需要编写大量代码, 为了简化编程, android提供了IntentService. IntentServiceService类的子类, 查看源代码可以知道IntentService只是将上例的单线程模型进行了简单的包装, handleMessage()方法中调用onHandleIntent()方法进行具体的请求处理, 该方法是一个抽象方法, 需要由开发者提供实现. 以下是IntentServiceService增强之处:

  • onCreate()方法中创建了一个子线程, 用于处理所有发送给onStartcommand()方法的intent.
  • onStartCommand()方法中将intentstartId存储在Message对象中, 并将该Message发送给子线程的消息队列. 因此同时存在多个启动请求时, 就会将这些请求的intentMessage的形式加入到子线程的消息队列中, 然后子线程从队列中不断的取出和处理消息.
  • 由子线程的Handler对象处理消息, Handler对象的handleMessage()方法调用onHandleIntent方法后调用了stopSelf(int)方法, 因此开发者无需考虑service的退出问题.
  • onHandleIntent方法是一个抽象方法, 留待开发者提供具体实现.

因此继承IntentService可以方便的构建单线程处理启动请求的service, 开发者不需要考虑创建线程, 创建Handler, service的退出等复杂的问题, 仅需要提供一个构造函数和实现onHandleIntent方法.

使用IntentService重写上面的例子:

public class SingleIntentService extends IntentService {
   public SingleIntentService() {
      // 设置子线程名称
      super("work thread");
   }
 
   @Override
   protected void onHandleIntent(Intent intent) {
      Log.d("SingleService", Thread.currentThread().getName());
      try {
         Thread.sleep(5 * 1000);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }
}

继承Service--并发处理多个请求

         为了并发处理多个请求, 可以在考虑在onStartCommand()方法中启动新的线程处理intent. 这样, 每调用一次startService()方法就会启动一个新的线程处理请求.

public class MultipleService extends Service {
   @Override
   public IBinder onBind(Intent intent) {
      return null;
   }
  
   @Override
   public int onStartCommand(Intent intent, int flags, final int startId) {
      new Thread() {
         public void run() {
            Log.d("SingleService", Thread.currentThread().getName());
            try {
                Thread.sleep(5 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stopSelf(startId);
         };
      }.start();
      return super.onStartCommand(intent, flags, startId);
   }
}
 

 

 

1
2
分享到:
评论

相关推荐

    android笔记--Service与AIDL

    这篇博客“android笔记--Service与AIDL”深入探讨了这两者在Android开发中的应用。 Service的基本概念: 1. Service是一种轻量级的后台组件,它可以持续运行,即使用户已经离开了应用程序。Service并不运行在单独的...

    梁劲机器学习笔记-全面简单Getting Started With MachineLearning (all in one)_部分2

    梁劲机器学习笔记-全面简单Getting Started With MachineLearning (all in one)_部分2。详细、明了地介绍了机器学习中的相关概念、数学知识和各种经典算法。以浅显易懂的方式去讲解它,降低大家的学习门槛。因为文件...

    新版Android开发教程&笔记--基础入门

    新版Android开发教程&笔记--基础入门一 新版Android开发教程&笔记--基础入门二 新版Android开发教程&笔记三--环境搭建与解析 新版Android开发教程&笔记四--Dalvik ADB 新版Android开发教程+笔记五--模拟器、应用1、2...

    Android学习笔记-service[参考].pdf

    - 内置队列处理请求,保证一次只有一个任务在执行。 - 请求完成后自动停止Service,无需手动调用`stopSelf()`。 - 提供默认的`onBind()`方法返回NULL,表明不支持绑定。 - `onStartCommand()`的默认实现将Intent...

    新版Android开发教程及笔记-完整版.pdf

    新版Android开发教程&笔记--基础入门一.pdf 新版Android开发教程&笔记--基础入门二.pdf 新版Android开发教程&笔记三--环境搭建与解析.pdf 新版Android开发教程&笔记四--Dalvik ADB.pdf 新版Android开发教程+笔记五--...

    Android-x86对于部分笔记本无法启动图形桌面的解决方案及相关调研1

    【Android-x86图形桌面无法启动的解决方案】 在尝试运行Android-x86系统于部分笔记本电脑上时,可能会遇到无法启动图形用户界面(GUI...每个设备可能存在差异,因此可能需要多次尝试和调试才能找到最适合的解决方案。

    Android--极简笔记App

    【Android 极简笔记App开发详解】 在移动设备上,笔记应用是不可或缺的一部分,而“Android--极简笔记App”正是这样一个基于Material Design设计规范的轻量级应用程序。这款应用利用了Android平台上的先进技术和...

    Android代码-Android_Learning_Notes

    4、Android04--Android服务 5、Android05--Android服务通信 6、Android06--Android广播接收器 7、Android07--Android日志系统 8、Android08--Android权限系统 用户界面 9、Android09--Fragment初探 10、Android09--...

    梁劲-机器学习笔记-全面简单Getting Started With MachineLearning (all in one)_部分1

    梁劲机器学习笔记-全面简单Getting Started With MachineLearning (all in one)_部分1。详细、明了地介绍了机器学习中的相关概念、数学知识和各种经典算法。以浅显易懂的方式去讲解它,降低大家的学习门槛。因为文件...

    Android学习笔记--Binder

    【Android学习笔记--Binder】 Binder是Android系统中的核心组件,它是Android系统实现进程间通信(IPC,Inter-Process Communication)的主要方式。Binder机制允许不同进程的组件之间进行数据交换和功能调用,就像...

    新版Android开发教程及笔记-完整版

    新版Android开发教程及笔记-完整版 比较不错的入门教程

    android学习笔记-clip.pdf

    android学习笔记-clip.pdf

    冰河的渗透实战笔记-冰河.pdf

    冰河整理的全网首个开源的以实战案例为背景的渗透实战笔记,全书共442页,共计37万字(不计空格)。整本书的内容涵盖:Kali基础、渗透工具、木马制作、钓鱼链接生成、爆破密码、内存溢出攻击、web渗透、数据提权、...

    Android自学笔记-9-Pull方式处理XML

    本自学笔记将深入探讨如何使用Pull解析器(PullParser)来处理XML,这是一种高效且内存友好的方式。 一、XML与Android XML(eXtensible Markup Language)是一种用于标记数据的语言,它定义了数据的结构和样式。在...

    pocket-note-android-口袋笔记-- 一个简单的记事本app.zip

    口袋笔记-- 一个简单的记事本app,具有多色彩主题,自带日历视图,记事可以是列表显示也可以是网格显示,提醒功能,隐私保护功能等。项目地址:https://github.com/channguyen/pocket-note-android 效果图: 

    Android代码-AndroidNote Android笔记

    Android学习笔记 > 十年生死两茫茫,不思量,自难忘,华年短暂,陈辞岁月悠悠伤, > 满腔热血已芜荒,展未来,后生强,战战兢兢,如履薄冰心彷徨, > 青丝化雪、鬓角成霜,已是英雄迟暮,人生怎慷慨激昂? 目录 ...

    Android学习笔记--Gson笔记

    这篇“Android学习笔记--Gson笔记”将深入探讨如何利用Gson来处理JSON数据,提升Android应用的数据解析效率。 一、Gson简介 Gson库能够将Java对象转换成对应的JSON字符串,反之亦然,这使得在Android应用中存储、...

    Android学习笔记-SQLite介绍-以及使用Sqlite-进行数据库的创建-完成数据.pdf

    Android学习笔记-SQLite介绍-以及使用Sqlite-进行数据库的创建-完成数据.pdf

    Android群英传笔记-----by ---------刘某人程序员

    其次,笔记深入讲解了Android应用程序的生命周期管理,包括Activity、Service、BroadcastReceiver和ContentProvider的创建与使用。这部分内容对于理解和控制应用的行为至关重要,能确保你的程序在不同场景下运行稳定...

Global site tag (gtag.js) - Google Analytics