Android源码之路(一、IntentService)
前言
源码分析篇,分析过程也参考过各位大神的成果。知识在于分享,学会了就是自己的,有参考过的,也会尽量给出链接(看了很多,可能无法一一给出);希望共同进步,站在巨人肩膀上看世界!
参考:http://blog.csdn.net/smbroe/article/details/45009721
以下用法和源码分析基于android-27(即版本android 8.1.0)
要点总结
1.生命周期onCreate --> onStartCommand --> onStart --> onHandleIntent --> onDestroy其中onCreate、onStartCommand、onStart、onDestroy运行在ui线程,onHandleIntent运行在子线程;2.如果每次onHandleIntent执行的时间足够长的话,连续循环启动IntentService的onCreate只会执行一次,而onStartCommand、onStart则启动几次就执行几次,onHandleIntent也是启动几次就执行几次,onDestroy只执行一次;对应onHandleIntent来说是串行的,对同一进程内同一IntentService来说必须按序排队依次执行;即如果IntentService未执行完任务时,不会再次启动新的IntentService,而是会使用原IntentService排队执行任务,全部任务执行完毕后,才退出IntentServie;3.如果启动IntentService时,前边的任务已经执行结束并退出后,则会再次创建onCreate并执行4.需要提供无参的构造函数,然后调用父类的有参构造;Service的实例化是系统来完成的,而且系统是用参数为空的构造函数来实例化Service的5.假设在onHandleIntent中创建handler并执行操作:@Overrideprotected void onHandleIntent(@Nullable Intent intent) {Log.d(TAG,"onHandleIntent"+" ,"+Thread.currentThread());Handler temphandler=new Handler(){@Overridepublic void handleMessage(Message msg) {Log.d(TAG,"handleMessage"+" ,"+Thread.currentThread());}};temphandler.sendEmptyMessageDelayed(1,5000);}这样handleMessage是不会执行的,因为此时temphandler获取的是intentService中HandlerThread的looper,而在onHandleIntent执行完后,会调用onDestroy退出整个消息队列,所以这边的handleMessage就执行不到了;如果temphandler是在外部初始化的就可以,默认会拿的mainlooper;
复制代码
优缺点
优点:
1.与service都运行于ui线程不同,intentService在子线程中处理耗时任务,避免堵塞造成anr;
2.自己维护消息队列,实现排队执行,避免多线程资源同步问题;
3.无需手动停止intentservice,任务都执行完毕后自动销毁;
4.存在已启动的正在使用的intentServie的话,再次启动不会重复创建,而是共用一个节省不必要资源开销
缺点:
- 1.处理完成之后要通知ui的话,相对麻烦,可能需要使用ui线程的handler或者广播。
使用方法
//创建实现IntentService的子类并在AndroidMainfest.xml中声明
<service android:name=".MyIntentService"></service>public class MyIntentService extends IntentService{String TAG="MyIntentService";public MyIntentService() { //需要提供默认的无参构造函数,然后调用父类的有参构造this("MyIntentService");}public MyIntentService(String name) {super(name);}@Overridepublic void setIntentRedelivery(boolean enabled) {super.setIntentRedelivery(enabled);Log.d(TAG,"setIntentRedelivery:"+enabled+" ,"+Thread.currentThread());}@Overridepublic void onCreate() {super.onCreate();Log.d(TAG,"onCreate"+" ,"+Thread.currentThread());}@Overridepublic void onStart(@Nullable Intent intent, int startId) {super.onStart(intent, startId);Log.d(TAG,"onStart"+" ,"+Thread.currentThread());}//这边的intent可以获取startService中传递进来的参数@Overridepublic int onStartCommand(@Nullable Intent intent, int flags, int startId) {Log.d(TAG,"onStartCommand:"+startId+" ,"+Thread.currentThread());return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG,"onDestroy"+" ,"+Thread.currentThread());}@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.d(TAG,"onBind"+" ,"+Thread.currentThread());return super.onBind(intent);}//这边的intent可以获取startService中传递进来的参数@Overrideprotected void onHandleIntent(@Nullable Intent intent) {Log.d(TAG,"onHandleIntent"+" ,"+Thread.currentThread());}
}//启动intentServiceIntent intent = new Intent(SecondActivity.this,MyIntentService.class);intent.putExtra("parmas1","abcd");//..按需要携带参数intent.putExtra("parmas2",true);SecondActivity.this.startService(intent);
复制代码
源码分析
onCreate函数
private volatile Looper mServiceLooper;private volatile ServiceHandler mServiceHandler;@Overridepublic void onCreate() {// TODO: It would be nice to have an option to hold a partial wakelock// during processing, and to have a static startService(Context, Intent)// method that would launch the service & hand off a wakelock.super.onCreate();HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");thread.start();mServiceLooper = thread.getLooper();mServiceHandler = new ServiceHandler(mServiceLooper);}
复制代码
在OnCreate中创建了一个HandlerThread,并获取其中的looper创建ServiceHandler(继承自Handler),使得ServiceHandler可以在子线程中处理消息
复制代码
onStartCommand函数
/*** You should not override this method for your IntentService. Instead,* override {@link #onHandleIntent}, which the system calls when the IntentService* receives a start request.* @see android.app.Service#onStartCommand*/@Overridepublic int onStartCommand(@Nullable Intent intent, int flags, int startId) {onStart(intent, startId);return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;}
复制代码
对于onStartCommand只是简单的调用了onStart方法
复制代码
onStart函数
@Overridepublic void onStart(@Nullable Intent intent, int startId) {Message msg = mServiceHandler.obtainMessage();msg.arg1 = startId;msg.obj = intent;mServiceHandler.sendMessage(msg);}
复制代码
在onStart方法中,所做的处理便是将startService传递过来的Intent和启动startId包装在Message中传递给ServiceHandler进行处理
复制代码
回调onHandleIntent处理消息
private final class ServiceHandler extends Handler {public ServiceHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {onHandleIntent((Intent)msg.obj);stopSelf(msg.arg1);}}
复制代码
而在ServiceHandler中,便是回调执行用户重写的onHandleIntent方法,
执行完毕之后,注意调用的stopSelf(startId),Handler中我们处理完每一个命令都会调用stopSelf(int)方法来停止服务:该方法需要来自onStartCommand方法中的启动ID,只有传入的startId是onStartCommand方法中接收到的最新启动ID时才会停止服务,就是说,我们的IntentService直到命令队列中的所有命令被执行完后才会停止服务。//会停止service并回调onDestroy
public final void stopSelf() {stopSelf(-1);
}//会判断传入的startId与当前startService所传入的startId是否一致,一致才停止Service并回调onDestroy,否则不停止,由此实现连续多次启动IntentService时,每次回调执行完onHandleIntent后,不会立即退出IntentService,而是接着执行Handler队列中的消息
public final void stopSelf(int startId) {if (mActivityManager == null) {return;}try {mActivityManager.stopServiceToken(new ComponentName(this, mClassName), mToken, startId);} catch (RemoteException ex) {}
}
复制代码
onDestroy函数
@Overridepublic void onDestroy() {mServiceLooper.quit();}
复制代码
退出消息队列
Android源码之路(一、IntentService)相关推荐
- Android源码之路(二、AsyncTask)
参考 https://www.baidu.com/link?url=QNRznJEBT25k0bpgVD3bOniOia2W85eiPIWrS93YFknyrHoFDGrJVtoax2ZYpiiErt ...
- 读万卷书不如行万里路,行万里路不如阅人无数,阅人无数不如名师指路,名师指路不如自己去悟,自己去悟不如分析android源码深处...
首先,作为一个已经学习android 一年多的人来说,如何选择android书籍,如何学习android 的app的开发,心中或多或少都有一些眉目,看了这本书的试读章节,真心感觉挺不错的.值得推荐,自 ...
- androidstudio调试android 源码 jni,在android studio下配置gradle用ndk-build和ndk-gbd编译调试JNI...
因为要在旧版android在做一些工作.所以做用到了它.目标平台是:android api 10和armv6. 开发环境是:AS 版本2.3.2; SDK版配android 2.3.3(api10); ...
- 大牛教你这样阅读android源码
当你去面试时,经常会被问到,你是否阅读过android系统源码?那系统源码该如何阅读呢? 下面,让我们来看看大牛们是如何阅读的(来自知乎的牛人们http://www.zhihu.com/questio ...
- 速通AOSP,成功编译调试Android源码
/ 今日科技快讯 / 近日据不少网友反馈,爱奇艺App开始对投屏功能作出限制,之前黄金VIP会员支持最高4K清晰度投屏,现在只能选最低的480P清晰度,要想进行4K投屏必须购买白金VIP会员. ...
- Android源码分析工具及方法
转载自:http://bbs.pediy.com/showthread.php?t=183278 标 题: [原创]Android源码分析工具及方法 作 者: MindMac 时 间: 2014-01 ...
- Android 源码分析工具
2019独角兽企业重金招聘Python工程师标准>>> 标 题: [原创]Android源码分析工具及方法 作 者: MindMac 时 间: 2014-01-02,09:32:35 ...
- Android源码编译详解【四】:Android 6.0_源码的下载与编译
1.AOSP源码下载 AOSP:即为"Android Open-Source Project"的缩写,中文意为 :"安卓开放源代码项目". Google官方 ...
- Android 源码编译详解【合集篇】
Android 源码编译详解[一]:服务器硬件配置及机型推荐 做 Android系统开发多年,开发环境都是入职就搭建好了,入职时拿个账号密码就直接开始搞开发了,年初换了新公司,所有的项目都是刚起步,一 ...
最新文章
- Python开发基础总结之函数+闭包+字典+列表
- SeciLog 1.3.1 发布,增加了全屏配置,自定义预警等新功能
- 《Groovy极简教程》第12章 Groovy的JSON包
- Git 经常使用命令总结
- 多个相同参数表单提交
- python 两阶段聚类_Python,如何对多元时间序列进行聚类?
- css 超出N行文本如何处理
- python视频处理代码_Python装逼指南——五行代码实现批量抠图,附视频抠图
- NDVI归一化差异植被指数
- 全自动高清录播服务器,高清高清录播服务器 高清全自动录播系统 方便携带 搭建快捷...
- oppoa5降级教程_OPPO A5官方出厂rom系统刷机包下载_卡刷升级包降级回退包
- java Base64带秘钥的加密解密
- 机器学习—确定系数R2
- 无法直接打开jar文件,提示“你要以何种方式打开.jar文件”(已解决)
- pandas parquet文件读取pyarrow、feather文件保存与读取;requests 或wget下载图片文件
- 入门级短信推送,你还不会吗?
- 计蒜客:Cryptographer's Conundrum
- 主题模型简介(topic model)
- VoLTE KPI指标分类和定义
- 2016年工作总结以及2017年工作计划
热门文章
- 华为鸿蒙系统发展时间2021年,耗时八年打造国产系统,华为鸿蒙OS质疑声不断,它才是真正未来...
- java mongocollection_MongoDb完结笔记-与java结合
- linux video属性_Linux 下Video 的制作方法
- 面试官问你Java内存区域你用new创建对象来解释
- C++特殊符号:【优先级】
- 【转】认识 C++ 中的 explicit 关键字
- WMI 获得已安装应用程序列表
- 08_提升方法Boosting1_统计学习方法
- redhat7 常用命令
- ios 判断某个时间是周几的方法