進(jìn)程劃分:(從高到底)
1摩骨、前臺(tái)進(jìn)程
①某進(jìn)程持有一個(gè)正在與用戶(hù)進(jìn)行交互的Activity并該Activity正在處于resume狀態(tài)
②某進(jìn)程持有一個(gè)Service大脉,并且該Service與用戶(hù)正在交互的Activity綁定
③某進(jìn)程持有一個(gè)Service,且該Service調(diào)用startForeground()方法使之位于前臺(tái)運(yùn)行苛败。
④某進(jìn)程持有一個(gè)Service满葛,且該Service正在執(zhí)行它的某個(gè)生命周期回調(diào)方法径簿,比如onCreate()、 onStart()或onDestroy()嘀韧。
⑤某個(gè)進(jìn)程持有一個(gè)BroadcastReceiver篇亭,并且該BroadcastReceiver正在執(zhí)行其onReceive()方法。
2锄贷、可見(jiàn)進(jìn)程
①擁有不在前臺(tái)但仍對(duì)用戶(hù)可見(jiàn)的Activity(已調(diào)用onPause)
②擁有綁定到可見(jiàn)Activity的Service
3暗赶、服務(wù)進(jìn)程 某個(gè)進(jìn)程中運(yùn)行著一個(gè)Service且該Service是通過(guò)startService()啟動(dòng)的,與用戶(hù)看見(jiàn)的界面沒(méi)有直接關(guān)聯(lián)肃叶。
4蹂随、后臺(tái)進(jìn)程 在用戶(hù)按了"back"或者"home"后,程序本身看不到了,但是其實(shí)還在運(yùn)行的程序,比如Activity調(diào)用了onPause方法
5因惭、空進(jìn)程 某個(gè)進(jìn)程不包含任何活躍的組件時(shí)該進(jìn)程就會(huì)被置為空進(jìn)程岳锁,完全沒(méi)用,殺了它只有好處沒(méi)壞處,第一個(gè)干它!
進(jìn)程回收機(jī)制
app在退出后臺(tái)時(shí)系統(tǒng)并不會(huì)真正的kill這個(gè)進(jìn)程,而是將其緩存起來(lái)蹦魔,打開(kāi)的應(yīng)用越多激率,后臺(tái)緩存的進(jìn)程也就越多,在系統(tǒng)內(nèi)存不足的情況下勿决,系統(tǒng)會(huì)依照自身進(jìn)程回收機(jī)制來(lái)判斷kill哪些進(jìn)程乒躺,以騰出內(nèi)存給需要的app
進(jìn)程回收機(jī)制就是根據(jù) oom_adj 這個(gè)優(yōu)先級(jí)來(lái)決定是否進(jìn)行回收 ①進(jìn)程的oom_adj 越大,表示優(yōu)先級(jí)越低低缩,越容易被回收嘉冒。反之。 ②普通app進(jìn)程oom_adj >=0咆繁,系統(tǒng)進(jìn)程的app的oom_adj 才可能<0
進(jìn)程被渫疲活方案:
黑色保活:
①開(kāi)機(jī)玩般,網(wǎng)絡(luò)切換银觅、拍照、拍視頻的時(shí)候坏为,利用系統(tǒng)產(chǎn)生的廣播喚醒a(bǔ)pp【但是究驴,最新的Android N已經(jīng)取消了開(kāi)機(jī),網(wǎng)絡(luò)切換匀伏、拍照洒忧、拍視頻三種廣播,而且開(kāi)機(jī)廣播的話帘撰,一些定制ROM的廠商早已將其去掉】
②接入第三方SDK也會(huì)喚醒相應(yīng)的app進(jìn)程跑慕,比如微信sdk會(huì)喚醒微信,支付寶sdk會(huì)喚醒支付寶
③假如你手機(jī)里裝了支付寶、淘寶核行、天貓牢硅、UC等阿里系的app,那么你打開(kāi)任意一個(gè)阿里系的app后芝雪,有可能就順便把其他阿里系的app給喚醒了减余。
白色保活: 調(diào)用系統(tǒng)api啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程惩系,這樣會(huì)在系統(tǒng)的通知欄生成一個(gè)Notification位岔,哪怕退到后臺(tái),用戶(hù)也是知道有這樣一個(gè)app在運(yùn)行著堡牡,比如QQ音樂(lè)等
灰色笔闾В活: 應(yīng)用范圍最廣范。是利用系統(tǒng)的漏洞來(lái)啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程晤柄,與普通的啟動(dòng)方式區(qū)別在于擦剑,它不會(huì)在系統(tǒng)通知欄處出現(xiàn)一個(gè)Notification,看起來(lái)就如同運(yùn)行著一個(gè)后臺(tái)Service進(jìn)程一樣芥颈。這樣做帶來(lái)的好處就是惠勒,用戶(hù)無(wú)法察覺(jué)到你運(yùn)行著一個(gè)前臺(tái)進(jìn)程(因?yàn)榭床坏絅otification),但你的進(jìn)程優(yōu)先級(jí)又是高于普通后臺(tái)進(jìn)程的。那么如何利用系統(tǒng)的漏洞呢爬坑,大致的實(shí)現(xiàn)思路和代碼如下:
思路一:API < 18纠屋,啟動(dòng)前臺(tái)Service時(shí)直接傳入new Notification()
; 思路二:API >= 18盾计,同時(shí)啟動(dòng)兩個(gè)id相同的前臺(tái)Service售担,然后再將后啟動(dòng)的Service做stop處理;
public class GrayService extends Service {
private final static int GRAY_SERVICE_ID = 1001;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT < 18) {
startForeground(GRAY_SERVICE_ID, new Notification());//API < 18 闯估,此方法能有效隱藏Notification上的圖標(biāo)
} else {
Intent innerIntent = new Intent(this, GrayInnerService.class);
startService(innerIntent);
startForeground(GRAY_SERVICE_ID, new Notification());
}
return super.onStartCommand(intent, flags, startId);
}
...
...
/**
* 給 API >= 18 的平臺(tái)上用的灰色弊粕幔活手段
*/
public static class GrayInnerService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(GRAY_SERVICE_ID, new Notification());
stopForeground(true);
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
}
}
使用灰色保活并不代表著你的Service就永生不死了涨薪,只能說(shuō)是提高了進(jìn)程的優(yōu)先級(jí)。如果你的app進(jìn)程占用了大量的內(nèi)存炫乓,按照回收進(jìn)程的策略刚夺,同樣會(huì)干掉你的app。 app退到后臺(tái)時(shí)末捣,其所有的進(jìn)程優(yōu)先級(jí)都會(huì)降低侠姑。但是UI進(jìn)程是降低最為明顯的,因?yàn)樗加玫膬?nèi)存資源最多箩做,系統(tǒng)內(nèi)存不足的時(shí)候肯定優(yōu)先殺這些占用內(nèi)存高的進(jìn)程來(lái)騰出資源莽红。所以,為了盡量避免后臺(tái)UI進(jìn)程被殺,需要盡可能的釋放一些不用的資源安吁,尤其是圖片醉蚁、音視頻之類(lèi)的。
其他方案:
JobSheduler: JobSheduler是作為進(jìn)程死后復(fù)活的一種手段鬼店,native進(jìn)程方式最大缺點(diǎn)是費(fèi)電网棍, Native 進(jìn)程費(fèi)電的原因是感知主進(jìn)程是否存活有兩種實(shí)現(xiàn)方式,在 Native 進(jìn)程中通過(guò)死循環(huán)或定時(shí)器妇智,輪訓(xùn)判斷主進(jìn)程是否存活滥玷,當(dāng)主進(jìn)程不存活時(shí)進(jìn)行拉活。其次5.0以上系統(tǒng)不支持巍棱。 但是JobSheduler可以替代在Android5.0以上native進(jìn)程方式惑畴,這種方式即使用戶(hù)強(qiáng)制關(guān)閉,也能被拉起來(lái)航徙,
粘性服務(wù)&與系統(tǒng)服務(wù)捆綁: 這個(gè)是系統(tǒng)自帶的如贷,onStartCommand方法必須具有一個(gè)整形的返回值,這個(gè)整形的返回值用來(lái)告訴系統(tǒng)在服務(wù)啟動(dòng)完畢后捉偏,如果被Kill倒得,系統(tǒng)將如何操作,這種方案雖然可以夭禽,但是在某些情況or某些定制ROM上可能失效霞掺,我認(rèn)為可以多做一種保守方案
START_STICKY 如果系統(tǒng)在onStartCommand返回后被銷(xiāo)毀,系統(tǒng)將會(huì)重新創(chuàng)建服務(wù)并依次調(diào)用onCreate和onStartCommand(注意:根據(jù)測(cè)試Android2.3.3以下版本只會(huì)調(diào)用onCreate根本不會(huì)調(diào)用onStartCommand讹躯,Android4.0可以辦到)菩彬,這種相當(dāng)于服務(wù)又重新啟動(dòng)恢復(fù)到之前的狀態(tài)了)。
START_NOT_STICKY 如果系統(tǒng)在onStartCommand返回后被銷(xiāo)毀潮梯,如果返回該值骗灶,則在執(zhí)行完onStartCommand方法后如果Service被殺掉系統(tǒng)將不會(huì)重啟該服務(wù)。
START_REDELIVER_INTENT START_STICKY的兼容版本秉馏,不同的是其不保證服務(wù)被殺后一定能重啟耙旦。