博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android笔记--处理started service的多次启动请求(转)
阅读量:6959 次
发布时间:2019-06-27

本文共 4830 字,大约阅读时间需要 16 分钟。

转自:http://coolxing.iteye.com/blog/1284476

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

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

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

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

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

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

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

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

 

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类. IntentService类Service类的子类, 查看源代码可以知道IntentService只是将上例的单线程模型进行了简单的包装, 在handleMessage()方法中调用onHandleIntent()方法进行具体的请求处理, 该方法是一个抽象方法,需要由开发者提供实现. 以下是IntentService对Service增强之处:

  • 在onCreate()方法中创建了一个子线程, 用于处理所有发送给onStartcommand()方法的intent.
  • 在onStartCommand()方法中将intent和startId存储在Message对象中, 并将该Message发送给子线程的消息队列. 因此同时存在多个启动请求时, 就会将这些请求的intent以Message的形式加入到子线程的消息队列中, 然后子线程从队列中不断的取出和处理消息.
  • 由子线程的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);   }}

 

转载于:https://www.cnblogs.com/pengyingh/articles/4839032.html

你可能感兴趣的文章
组策略 之 正确理解STARTER GPO
查看>>
分布式搜索elasticsearch的5种分片查询优先级
查看>>
python + selenium 弹出Alert提示窗, 自动确认。python语法注意
查看>>
PHP htmlspecialchars和htmlspecialchars_decode(函数)
查看>>
adt-bundle-windows-x86 出现的问题
查看>>
VHD and BitLocker
查看>>
我的友情链接
查看>>
菊花新
查看>>
OpenCASCADE Conic to BSpline Curves-Circle
查看>>
cacti监控
查看>>
ocp 052最新题库分享 20180530 又一次变题
查看>>
数据结构之二叉树(前序 中序 后续线索话非递归方式)
查看>>
CSS选择器
查看>>
[警告]Duplicating managed version 4.12 for junit
查看>>
性能测试培训:WebSocket协议的接口性能之Jmeter
查看>>
2012年50个顶级的photoshop教程:(一)图形绘画类
查看>>
Linux-RHEL 7.2实验环境的搭建
查看>>
【安全牛学习笔记】端口扫描(二)
查看>>
php 获取月第一天和最后一天
查看>>
CentOS Linux安装JDK
查看>>