IntentService详解
IntentService是什么?
这篇文章是之前就写好的,一直没有整理出来,这几天有空正好整理发布一下。
我们知道Service可以让我们在后台处理一些事情,但是Service实际上也是主线程,所以执行长耗时任务时依然会ANR,只不过ANR触发时间要比前台长。一般我们会在Service中开启一个子线程去完成耗时任务。
而IntentService就是解决这个问题的,它是Service的一个抽象子类,需要实现onHandleIntent,代码在这个函数中执行。它与Service最大的不同就是默认开启一个子线程,而onHandleIntent就是在子线程中执行的。
所以IntentService就是一个自带子线程的Service。
那么它是如何实现的,我们通过它的源码来简单分析一下。
线程的创建
IntentService的源码其实不多,先来看看它的onCreate函数
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
复制代码
在onCreate中会创建并启动一个HandlerThread。这个HandlerThread是Thread的一个子类,通过它的源码可以看到实际上就是默认绑定开启了looper,它的run函数如下:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
复制代码
可以看到绑定并启动了一个looper,而它的其他函数则都与looper和handler的操作有关,这里不一一看了。
回到onCreate中,接下来的代码则是通过HandlerThread的looper创建了一个ServiceHandler,这是一个内部类,源码如下:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
复制代码
可以看到在handleMessage中调用了onHandleIntent
,这样函数中的代码就在这个HandlerThread的子线程中运行。
然后执行了stopSelf
函数,这个函数是Service的,用于停止服务的,与context的stopService
效果是一样的。
也就是说IntentService执行onHandleIntent
后就会试图停止服务,但是这里还有一些逻辑,注意传參是msg.arg1
,这个很重要,后面会再详谈。
线程运行
通过上面我们知道,IntentService创建时开启一个线程并启动一个looper,并且通过ServiceHandler来执行代码。但是想要执行onHandleIntent
,一定需要sendMessage,那么在哪send的呢?
答案是在Service的start周期中,如下:
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
复制代码
可以看到在onStart
中组合了一个msg并send,这样就实现了服务一启动就自动执行onHandleIntent
。注意msg的arg1参数赋值是startId,结合上面所说的就是执行onHandleIntent
后会执行stopSelf(startId)
。
上面我们说过stopSelf
会试图停止服务,为什么是试图而不是一定,关键就是startId这里。
只有当stopSelf
函数的startId与Service当前的startId相同,才会停止服务,主要是针对多次startService
的情况。
当我们多次startService
的时候,startId会自动递增,并且保存最后一个startId。
所以多次startService
,onHandleIntent
会执行多次,因为前几次执行到stopSelf
时startId不同,只有当最后一个执行完后才真正的停止服务。
但是注意,在onBind
函数中并没有sendMessage
,所以IntentService需要使用start的方式,bind的方式由于不会走onStart这个周期,所以onHandleIntent
不会执行。
退出线程
在创建线程时默认开启了looper,looper其实就是一个死循环,所以这个线程会一直阻塞。那么IntentService如何退出这个线程?
上面我们知道最后通过stopSelf停止服务,但是还没有看到对线程的操作。但是当我们停止服务时,会执行onDestroy函数,来看看源码:
@Override
public void onDestroy() {
mServiceLooper.quit();
}
复制代码
这里将looper退出了,这样线程循环结束了线程就退出了。所以IntentService停止线程就会退出,如果多次启动service,那么最后一个执行完才会退出线程,这样也保证了任务全部被执行。
总结
IntentService其实很简单,就是内部实现了一个使用Handler机制的子线程而已,但是它使用起来方便了很多。
相关文章
- 【项目实战典型案例】07.在线人员列表逻辑混乱反例
- 高频前端面试题之HTML篇(四)
- VSCode 当笔记工具
- web3:区块链共识机制系列-POS(Proof of Stake)股权证明算法
- 【小程序】常见系统API | 页面分享 | 位置信息 | 本地存储
- 同态加密详解
- 【区块链实战】什么是 P2P 网络,区块链和 P2P 网络有什么关系
- 给程序员的Web3入门指南
- VSCode常用快捷键(Mac版)
- 基于区块链/Hyperledger Fabric的商品交易溯源系统搭建步骤
- 【区块链实战】如何创建一个带参数的智能合约
- 区块链开发完整指南。如何开发一款区块链项目?
- 经典同态加密算法Paillier解读 - 原理、实现和应用
- 【Zookeeper 初级】02、Zookeeper 集群部署
- 华为OD机试 - 二维矩阵的最大值(JavaScript) | 机试题+算法思路+考点+代码解析 【2023】
- 学习操作系统的必备教科书《操作系统:原理与实现》| 文末赠书4本
- 对于从事芯片行业的人来说,有哪些知识是需要储备的?
- FinOps,从概念到落地 | UGeek大咖说第一期直播回顾(上)
- 【Kubernetes】第二十七篇 - 布署前端项(下)
- 从0开始学python -56