IntentService源码分析

Posted 爱coding的卖油翁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IntentService源码分析相关的知识,希望对你有一定的参考价值。

IntentService是Service类的子类,用来处理异步请求。客户端可以通过startService(Intent)方法传递请求给IntentService。IntentService在onCreate()函数中通过HandlerThread单独开启一个线程来处理所有Intent请求对象(通过startService的方式发送过来的)所对应的任务,这样以免事务处理阻塞主线程。执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;否则执行下一个Intent请求所对应的任务。

通常Service都是运行在主线程中,如果我们在Service中做一些耗时操作,可能会引起ANR。IntentService通过简单的封装,帮我们解决了这个问题,只需要直接调用就可以了。

但是IntentService不支持多线程,如果你有多线程的操作需求,可能需要单独修改了。

这就是 IntentService 的简单用法。基于Android源码24分析。

全局变量

我们可以看到有一个ServiceHandler的内部类,继承自Handler,在handleMessage()方法中,回调了onHandleIntent()方法,然后调用stopSelf()方法杀死自己。

还有一个Looper变量,mServiceLooper和mServiceHandler都是用volatile关键字来修饰的,查了一下资料关于volatile的作用,主要在多线程访问的时候,对变量的可见性进行了控制,当一个线程修改了mServiceHandler的值,另一个现场立马能够获取到。(如果理解的不对,望指正)

String类型的mName,就是IntentService中工作线程的名字。

Boolean类型的mRedelivery,默认为false,它的作用很重要,后面会来讲到它。

方法分析

我们看它的构造方法,传入了一个string,赋值给了nName,我们传入进来的字段就是工作线程的名字。在我们继承IntentService时,会提示实现一个构造函数,其中就要传入一个String类型的名称进来,不然编译会报错。

我们可以看到onBind()返回为空,什么事都没做,所以如果你使用bindService的方法来启动一个IntentService,是没有意义的。必须要以startService()方法来启动服务。

可以看到在onCreate里面初始化了一个HandlerThread,然后用该HandlerThread的Looper赋值给全局变量mServiceLooper, 在用mServiceLooper去初始化ServiceHandler。这样ServiceHandler就用的是子线程的Looper,所以handleMessage()方法也是运行在子线程中的,handleMessage中的onHandleIntent()和stopSelf()方法自然也是运行在子线程中的。

在你的IntentService中,不需要重写onStartCommand()方法,相反的,只要重写onHandleIntent()方法,当IntentService接收到一个开始的请求时就会回调onHandleIntent()方法。

当我们调用startService方法启动服务时,首先会去调用onCreate()初始化上面分析的一些参数,然后调用onStartCommand()方法,在onStartCommand()方法中,会再去调用onStart()方法,并将intent和startId传入。

在最后,它会根据全局变量mRedelivery的值来判定是返回START_REDELIVER_INTENT或者是START_NOT_STICKY,默认返回START_NOT_STICKY。

那这两个值有什么用呢?

  • START_NOT_STICKY:如果进程死亡,intent随之死亡。
  • START_REDELIVER_INTENT:如果onHandleIntent()返回之前进程死掉了,那么进程将会重新启动,intent重新投递,如果有大量的intent投递了,那么只保证最近的intent会被重投递。

提供了一个setIntentRedelivery()方法,用来设置mRedelivery的值,也就是onStartCommand的返回值。

在onStart()方法中,会先通过ServiceHandler对象去获取Message对象,之后将消息的arg1字段设置为startId,obj字段设置为intent,最后调用ServiceHandler对象将这条消息发送出去。

这样,ServiceHandler中的handleMessage()方法就会被回调,在handleMessage()方法中会调用onHandleIntent()方法。

在最后会调用stopSelf(msg.arg1)方法,注意这个msg.arg1是个int值,相当于一个请求的唯一标识。每发送一个请求,会生成一个唯一的标识,然后将请求放入队列,当全部执行完成。(最后一个请求也就相当于getLastStartId == startId),或者当前发送的标识是最近发出的那一个(getLastStartId == startId),则会销毁我们的Service.

如果传入的是-1则直接销毁。

当任务完成销毁,Service就会回调onDestory()方法,可以看到在onDestroy()中释放了我们的Looper, mServiceLooper.quit()。

那么,IntentService的源码基本上就全部看完了,只有区区100多行,真是短小精悍呀~

以上是关于IntentService源码分析的主要内容,如果未能解决你的问题,请参考以下文章

IntentService 源码分析

IntentService源码分析

IntentService使用以及源码分析

IntentService源码分析

Android IntentService源码理解 及 HandlerThread构建消息循环机制分析

源码分析Service和IntentService的区别