四大组件之Service详解

生命周期

694018-99da2307c5d69134.jpg

从图中可以看出Service的生命周期会根据启动方式的不同有不同的生命周期回调。两种启动方式分别是startService和bindService。

  1. 两种启动方式的生命周期
  • startService的生命周期是:onCreate() -> onStart() -> onDestroy()
  • bindService的生命周期是:onCreate() -> onBind() -> onUnbind() -> onDestroy()
  1. 两种启动方式的区别
  • 用startService方法开启服务,这个Service和Client之间没有联系,Service的运行和Client是相互独立的,想结束这个Service的话,就在Service本身中调用stopSelf()方法结束服务或者Client调用Service的stopService()方法。
  • 用bindService方法开启服务,这个Service和Client是有绑定关系的,可以进行数据交互(使用Binder的代理对象),想要结束这个Service,可以通过调用unbindService()方法,或者调用的Client被销毁,绑定的Service也会随之销毁。
  1. 一个Service只有一个实例onCreate()只有在第一次Service实例被创建的时候才会调用,即在Service没被销毁前无论调用startService或bindService多少次,onCreate()只有在第一次才会执行,所以一般在这里做一些初始化工作,比如创建数据缓存,线程池等;onBind()也只有在第一次被绑定时调用,即多次的bindService,onBind()只在第一次绑定的时候调用。
  • 当startService单独使用时,即使对应的startService时传入的Context被销毁,Service也还是会处于运行状态。

  • 无论多少个Activity绑定了Service,但是onBind()只会执行一次,也就是Service首次被绑定时会执行,onUnbind()也是如此,即最后一个Context失效后,才会执行onUnbind()(Activity主动调用unbindService或者被onDestory)。
    如果由于Activity没有主动调用unbindService与Serivice解绑,这样会造成内存泄漏.

  • 如果是多个Activity都绑定了同一个Service绑定,且没有执行过startService,当其中一个Activity onDestory或者进行unbindService之后,其与Service进行bindService时的Context就会失效,而当最后与Service绑定的Contxet失效后,Service才会执行onUnbind(),之后会自动调用onDestory()进行销毁。

  • 如果是同时有多个Activity对Service进行了startService和bindService,如果没有显示调用过stopService,则当所有与Service绑定的Context失效后,Service不会被销毁,会一直在后台运行,因为有主动调用了startService,此时必须主动调用stopService或者在Service中调用stopSelf才能将其销毁;而如果在一个或者多个Context失效前主动调用了stopService或者在Service中调用stopSelf,则需要等到最后一个Context主动与Service进行unbindService或者失效后,才会能使Service执行onDestory。

  1. 默认情况下,服务是运行在主线程的,但这不符合我们使用服务的初衷(除非想提高服务优先级不被杀掉)所以一般要在服务运行耗时操作需要在服务中开启子线程。

本地服务和远程服务

  1. 本地服务
    本地服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外本地服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多,当主进程被Kill后,服务便会终止。一般使用在音乐播放器播放等不需要常驻的服务。指的是服务和启动服务的activity在同一个进程中。

  2. 远程服务
    远程服务是独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。一般定义方式 android:process=":remote" 由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。由于是独立的进程,会占用一定资源,并且使用AIDL进行IPC比较麻烦。一般用于系统的Service,这种Service是常驻的。指的是服务和启动服务的activity不在同一个进程中。
    注意:启动本地服务用的是显式启动;远程服务的启动要用到隐式启动

IntentService

IntentService是Android中提供的后台服务类,继承于Service,我们在外部组件中通过Intent向IntentService发送请求命令,之后IntentService逐个执行命令队列里的命令,接收到首个命令时,IntentService就开始启动并开始一条后台线程执行首个命令,接着队列里的命令将会被顺序执行,最后执行完队列的所有命令后,服务也随即停止并被销毁。

  1. 与Service的区别
  • Service中的程序仍然运行于主线程中,而在IntentService中的程序运行在我们的异步后台线程中。
  • 在Service中当我的后台服务执行完毕之后需要在外部组件中调用stopService方法销毁服务,而IntentService并不需要,它会在工作执行完毕后自动销毁。

如何让服务不被杀死

  1. non-sticky服务和sticky服务:
    non-sticky服务会在自己认为任务完成时停止,若一个Service为non-sticky服务则应该在onStartCommand方法中返回START_REDELIVER_INTENT或START_NOT_STICKY标志。sticky服务会持续存在,直到外部组件调用Context.stopService方法。sticky服务返回标志位START_STICKY。默认是non-sticky服务。

为了式服务不被杀死,可以使用sticky,在onStartCommand中直接返回START_STICKY

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
//        return super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

当Service因内存不足而被系统kill后,一段时间后内存再次空闲时,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand方法,但其中的Intent将是null,除非有挂起的Intent,如pendingintent,这个状态下比较适用于不执行命令、但无限期运行并等待作业的媒体播放器或类似服务。

  1. 提高Service优先级
<service
android:name="com.dbjtech.acbxt.waiqin.UploadService"
android:enabled="true">
<intent-filtera android:priority="1000">
<action android:name="com.dbjtech.myservice"/>
</intent-filter>
</service>
  1. 在onDestroy方法里重启Service
    当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service;
  2. 提升Service进程的优先级
    进程优先级由高到低:前台进程 一 可视进程 一 服务进程 一 后台进程 一 空进程
    可以使用startForeground将service放到前台状态,这样低内存时,被杀死的概率会低一些;
  3. 系统广播监听Service状态
  4. 将APK安装到/system/app,变身为系统级应用

以上机制都不能百分百保证Service不被杀死,除非做到系统白名单,与系统同生共死。

Service启动过程

==启动流程==:

  1. Process A进程采用Binder IPC向system_server进程发起startService请求;
  2. system_server进程接收到请求后,向zygote进程发送创建进程的请求;
  3. zygote进程fork出新的子进程Remote Service进程;
  4. Remote Service进程,通过Binder IPC向sytem_server进程发起attachApplication请求;
  5. system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向remote Service进程发送scheduleCreateService请求;
  6. Remote Service进程的binder线程在收到请求后,通过handler向主线程发送CREATE_SERVICE消息;
  7. 主线程在收到Message后,通过发射机制创建目标Service,并回调Service.onCreate()方法。

到此,服务便正式启动完成。==当创建的是本地服务或者服务所属进程已创建时,则无需经过上述步骤2、3,直接创建服务即可==。

image.png

在整个startService过程,从进程角度看服务启动过程,涉及4个进程:

  1. Process A进程:是指调用startService命令所在的进程,也就是启动服务的发起端进程,比如点击桌面App图标,此处Process A便是Launcher所在进程。
  2. system_server进程:系统进程,是java framework框架的核心载体,里面运行了大量的系统服务,比如这里提供ApplicationThreadProxy(简称ATP),ActivityManagerService(简称AMS),这个两个服务都运行在system_server进程的不同线程中,由于ATP和AMS都是基于IBinder接口,都是binder线程,binder线程的创建与销毁都是由binder驱动来决定的,每个进程binder线程个数的上限为16。
  3. Zygote进程:是由init进程孵化而来的,用于创建Java层进程的母体,所有的Java层进程都是由Zygote进程孵化而来;
  4. Remote Service进程:远程服务所在进程,是由Zygote进程孵化而来的用于运行Remote服务的进程。主线程主要负责Activity/Service等组件的生命周期以及UI相关操作都运行在这个线程; 另外,每个App进程中至少会有两个binder线程 ApplicationThread(简称AT)和ActivityManagerProxy(简称AMP),当然还有其他线程,这里不是重点就不提了。

参考链接:
https://blog.csdn.net/qq_22804827/article/details/78609636

https://blog.csdn.net/weixin_39460667/article/details/82770164

https://www.cnblogs.com/it-tsz/p/11601265.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容

  • 新来的员工大明,有个好习惯,不论什么来电,不论有多忙,都要将第一次来电的电话在自己的手机上“新建联系人”,并规规矩...
    w小郭阅读 209评论 0 1
  • 你是我心中的一根刺 拔掉会流很多的血 不拔一直刺疼着我 让我难以抉择 你 怎么就变成了一根刺呢
    善良的人家阅读 1,100评论 5 17
  • 每日目标 1.舌诊✅ 2.运动✅ 3.考证复习❌ 今天听了大hi的单一事件复盘。讲了她从开始决定运动到确定运...
    2020亲子同修阅读 131评论 0 0
  • 首先,运用各种渠道搜集资料。未来的发展很重要,要让那些能够改变你事业前途的人知道你表现得很好。 如果你不知道公司为...
    叮噹_喵阅读 126评论 0 1
  • 2019年的农历新年将近,年纪虽长,但是心态越发活泼。 去年的春节对于我来说,比以往沉重些,1人独自面对七姑八婆的...
    刘红leona阅读 262评论 0 2