1. 程式人生 > >Android如何讓APP程序常駐記憶體?

Android如何讓APP程序常駐記憶體?

如何讓Android程式常駐記憶體,像QQ一樣擁有強勁的生命力不被系統殺死?它傳說中的程序保活(人類也在探索永生不死,App亦然),本文將會介紹程序保活的黑魔法,我想絕大部分開發者都會對它感興趣。

程序保活的常見方案

黑色保活

何為黑色保活?就是利用不同App程序用廣播相互喚醒。例如:

  • 開機、網路切換、拍照、利用系統產生的廣播喚醒app。
  • 接入SDK,比如微信SDK會喚醒微信,支付寶SDK會喚醒支付寶。
  • 假如你的手機安裝了支付寶,淘寶等阿里系的app,那麼你開啟任意一個阿里系app後,就可以喚醒其他的阿里系app

    目前Google已經意識到這些問題,所以在Android N中取消了ACTION_NEW_PICTURE,CONNECTIVITY_ACTION等廣播。

白色保活

這種程序保活方式非常簡單,就是採用系統介面,啟動前臺Service,這樣你會在通知欄看到一個Notification,讓使用者明確的感知到你在執行中。

灰色保活

這種保活手段目前應用非常廣泛,它利用系統漏洞啟動一個前臺Service,與白色保活的區別在於,它不會在通知欄顯示Notification,這樣一來使用者就無法察覺到執行著一個前臺程序,但是你的程序優先順序又是高於普通後臺程序的。 目前很多app都採用灰色保活手段(微信,QQ),接下來我們一起來驗證一下。以微信為例,首先開啟微信,然後home鍵,確認通知欄無Notification,然後進入adb shell執行如下shell命令: dumpsys activity services com.tencent.mm

dumpsys_activity_services

通過以上命令,打印出指定包名程序中的Service資訊,你會看到isForeground=true的資訊,但是通知欄卻沒有看到Notification。這就是程序保活的黑魔法。

程式碼實現

我將其命名位GohnsonSerivice(強生服務,正所謂人如其名),具有強大生命力的服務。

1234567891011121314151617181920212223242526272829publicclassGohnsonServiceextendsService{privatefinalstaticintGOHNSON_ID=1000;@OverridepublicintonStartCommand
(Intent intent,intflags,intstartId){if(Build.VERSION.SDK_INT<18){startForeground(GOHNSON_ID,newNotification());}else{Intent innerIntent=newIntent(this,GohnsonInnerService.class);startService(innerIntent);startForeground(GOHNSON_ID,newNotification());}returnsuper.onStartCommand(intent,flags,startId);}publicstaticclassGohnsonInnerServiceextendsService{@OverridepublicintonStartCommand(Intent intent,intflags,intstartId){startForeground(GOHNSON_ID,newNotification());stopForeground(true);stopSelf();returnsuper.onStartCommand(intent,flags,startId);}}}

接下來你需要做的就是在Manifest中註冊服務。以及在app中啟動Service。這樣一來你的Service就能實現灰色保活了

灰色保活並不代表你的Service能夠永生,只能說明是提高了程序優先順序。如果你的app程序佔用了大量的系統資源,按照系統程序回收的策略,同樣會kill你的app。為了進行對比,我加入了一個普通的Service程序NormalService

1 2 3 4 <service android:name="com.vjson.gohnson.GohnsonService"android:process=":gohnson"/> <service android:name="com.vjson.gohnson.GohnsonService$GohnsonInnerService"/> <service android:name="com.vjson.gohnson.NormalService"android:process=":normal"/>

程序回收策略

出於效能上的考慮,app在後臺時系統並不會立即kill它,而是將其快取起來。開啟的應用越多,後臺快取的程序也越多。在系統資源不足的情況下,會根據程序回收機制來決定要kill掉哪些程序,以騰出資源來供給需要的app。這套策略就是Low Memory Killer ,它是基於Linux核心的 OOM Killer(Out-Of-Memory killer)機制誕生。

如何判斷程序的優先順序呢?

我們知道程序回收是依賴程序優先順序進行的,那麼如何判斷程序的優先順序高低呢?那就需要了解oom_adj:

它是Linux核心分配每個程序的一個值,代表程序優先順序,程序回收時就是依據它來決定是否回收。其值越大程序優先順序越低,越容易被回收,並且普通的app程序oom_adj>=0,系統程序的oom_adj才可能<0

下面以Demo為例,檢視其程序的oom_adj(注意以下測試結果中的oom_adj數值在不同裝置上結果不一樣

ps |grep com.vjson.gohnsonservice

  • UI程序:com.vjson.gohnsonservice
  • 灰色保活程序:com.vjson.gohnsonservice:gohnson
  • 普通後臺程序:com.vjson.gohnsonservice:normal cat /proc/程序ID/oom_adj

cat_proc_oom_adj

從上圖可以看到UI程序的oom_adj=0,保活程序oom_adj=2,普通後臺程序oom_adj=8。然後按home鍵將app切到後臺,在觀察各個程序oom_adj的值變化。你會發現UI程序的值變大了。

以上測試結果可以看出,灰色保活服務程序的優先順序明顯高於普通後臺服務程序,UI程序位於前臺時優先順序非常高,切到後臺之後oom_adj明顯增大(程序優先順序明顯降低)。由於UI程序佔用的資源最多,系統資源不足時肯定優先殺掉這些資源咱用高的程序以騰出資源。所以為了儘量避免後臺UI程序被殺,要儘可能的釋放不用的資源。

總結

記憶體保活是一把雙刃劍,用得好可以提升使用者體驗,用的不好那就是Android系統中的牛皮癬。