1. 程式人生 > >Android開發之如何保證Service不被殺掉(broadcast+system/app)

Android開發之如何保證Service不被殺掉(broadcast+system/app)



序言

最近專案要實現這樣一個效果:執行後,要有一個service始終保持在後臺執行,不管使用者作出什麼操作,都要保證service不被kill,這可真是一個難題。參考了現今各種定製版的系統和安全廠商牛虻軟體,如何能保證自己的Service不被殺死呢?

其實除了常規的手段,我們可以參考一下微信和360,設定-程式-正在執行,可以看到微信是同時開啟了兩個程序和服務:

【有興趣可以研究一下 守護程序 和 AIDL 


我猜想它應該是相互監聽,如果有一方被kill掉,另一個捕獲到立即啟動,以達到service永遠都在執行的狀態,貌似360也是這個原理,具體是不是這個樣子,還有待參考,目前我還沒有參透它們是如何實現的,先簡單說一下我自己的防控措施吧,首先介紹一下Service概念,記性不好,重複造一下車輪,高手可以直接看最後。

Service簡介

Service是在一段不定的時間執行在後臺,不和使用者互動應用元件。每個Service必須在manifest中 通過<service>來宣告。可以通過contect.startservice和contect.bindserverice來啟動。和其他的應用元件一樣,執行在程序的主執行緒中。這就是說如果service需要很多耗時或者阻塞的操作,需要在其子執行緒中實現(或者用系統提供的IntentService,它繼承了Service,它處理資料是用自身新開的執行緒)。【當然你也可以在新的執行緒中startService,這樣Service就不是在MainThread了

本地服務 Local Service 用於應用程式內部

它可以啟動並執行,直至有人停止了它或它自己停止。在這種方式下,它以呼叫Context.startService()啟動,而以呼叫Context.stopService()結束。它可以呼叫Service.stopSelf() 或 Service.stopSelfResult()來自己停止。不論呼叫了多少次startService()方法,你只需要呼叫一次stopService()來停止服務。

【用於實現應用程式自己的一些耗時任務,比如查詢升級資訊,並不佔用應用程式比如Activity所屬執行緒,而是單開執行緒後臺執行,這樣使用者體驗比較好】

遠端服務 Remote Service 用於Android系統內部的應用程式之間

它可以通過自己定義並暴露出來的介面進行程式操作。客戶端建立一個到服務物件的連線,並通過那個連線來呼叫服務。連線以呼叫Context.bindService()方法建立,以呼叫 Context.unbindService()關閉。多個客戶端可以繫結至同一個服務。如果服務此時還沒有載入,bindService()會先載入它。

【可被其他應用程式複用,比如天氣預報服務,其他應用程式不需要再寫這樣的服務,呼叫已有的即可】

1,Service的生命週期


2,Service執行方式

以startService()啟動服務,系統將通過傳入的Intent在底層搜尋相關符合Intent裡面資訊的service。如果服務沒有啟動則先執行onCreate,然後執行onStartCommand (可在裡面處理啟動時傳過來的Intent和其他引數),直到明顯呼叫stopService或者stopSelf才將停止Service。無論執行startService多少次,只要呼叫一次stopService或者stopSelf,Service都會停止。使用stopSelf(int)方法可以保證在處理好intent後再停止。onStartCommand ,在2.0後被引入用於service的啟動函式,2.0之前為public void onStart(Intent intent, int startId) 。

以bindService()方法啟用服務,呼叫者與服務繫結在了一起,呼叫者一旦退出,服務也就終止。onBind()只有採用Context.bindService()方法啟動服務時才會回撥該方法。該方法在呼叫者與服務繫結時被呼叫,當呼叫者與服務已經繫結,多次呼叫Context.bindService()方法並不會導致該方法被多次呼叫。採用Context.bindService()方法啟動服務時只能呼叫onUnbind()方法解除呼叫者與服務解除,服務結束時會呼叫onDestroy()方法。

3,擁有service的程序具有較高的優先順序

官方文件告訴我們,Android系統會盡量保持擁有service的程序執行,只要在該service已經被啟動(start)或者客戶端連線(bindService)到它。當記憶體不足時,需要保持,擁有service的程序具有較高的優先順序。

1. 如果service正在呼叫onCreate,onStartCommand或者onDestory方法,那麼用於當前service的程序則變為前臺程序以避免被killed。
2. 如果當前service已經被啟動(start),擁有它的程序則比那些使用者可見的程序優先順序低一些,但是比那些不可見的程序更重要,這就意味著service一般不會被killed.
3. 如果客戶端已經連線到service (bindService),那麼擁有Service的程序則擁有最高的優先順序,可以認為service是可見的。
4. 如果service可以使用startForeground(int, Notification)方法來將service設定為前臺狀態,那麼系統就認為是對使用者可見的,並不會在記憶體不足時killed。
5. 如果有其他的應用元件作為Service,Activity等執行在相同的程序中,那麼將會增加該程序的重要性。

保證service不被殺掉

onStartCommand方法,返回START_STICKY

StartCommond幾個常量引數簡介:

1、START_STICKY

在執行onStartCommand後service程序被kill後,那將保留在開始狀態,但是不保留那些傳入的intent。不久後service就會再次嘗試重新建立,因為保留在開始狀態,在建立     service後將保證呼叫onstartCommand。如果沒有傳遞任何開始命令給service,那將獲取到null的intent。

2、START_NOT_STICKY

在執行onStartCommand後service程序被kill後,並且沒有新的intent傳遞給它。Service將移出開始狀態,並且直到新的明顯的方法(startService)呼叫才重新建立。因為如果沒有傳遞任何未決定的intent那麼service是不會啟動,也就是期間onstartCommand不會接收到任何null的intent。

3、START_REDELIVER_INTENT

在執行onStartCommand後service程序被kill後,系統將會再次啟動service,並傳入最後一個intent給onstartCommand。直到呼叫stopSelf(int)才停止傳遞intent。如果在被kill後還有未處理好的intent,那被kill後服務還是會自動啟動。因此onstartCommand不會接收到任何null的intent。

  1. @Override
  2. publicint onStartCommand(Intent intent, int flags, int startId) {  
  3.     flags = START_STICKY;  
  4.     returnsuper.onStartCommand(intent, flags, startId);  
  5. }  

【結論】 手動返回START_STICKY,親測當service因記憶體不足被kill,當記憶體又有的時候,service又被重新建立,比較不錯,但是不能保證任何情況下都被重建,比如程序被幹掉了....

提升service優先順序

在AndroidManifest.xml檔案中對於intent-filter可以通過android:priority = "1000"這個屬性設定最高優先順序,1000是最高值,如果數字越小則優先順序越低,同時適用於廣播。

  1. <service  
  2.     android:name="com.dbjtech.acbxt.waiqin.UploadService"
  3.     android:enabled="true" >  
  4.     <intent-filter android:priority="1000" >  
  5.         <action android:name="com.dbjtech.myservice" />  
  6.     </intent-filter>  
  7. </service>  

【結論】目前看來,priority這個屬性貌似只適用於broadcast,對於Service來說可能無效

提升service程序優先順序

Android中的程序是託管的,當系統程序空間緊張的時候,會依照優先順序自動進行程序的回收。Android將程序分為6個等級,它們按優先順序順序由高到低依次是:

   1.前臺程序( FOREGROUND_APP)
   2.可視程序(VISIBLE_APP )
   3. 次要服務程序(SECONDARY_SERVER )
   4.後臺程序 (HIDDEN_APP)
   5.內容供應節點(CONTENT_PROVIDER)
   6.空程序(EMPTY_APP)

當service執行在低記憶體的環境時,將會kill掉一些存在的程序。因此程序的優先順序將會很重要,可以使用startForeground 將service放到前臺狀態。這樣在低記憶體時被kill的機率會低一些。

在onStartCommand方法內新增如下程式碼:

  1.  Notification notification = new Notification(R.drawable.ic_launcher,  
  2.  getString(R.string.app_name), System.currentTimeMillis());  
  3.  PendingIntent pendingintent = PendingIntent.getActivity(this0,  
  4.  new Intent(this, AppMain.class), 0);  
  5.  notification.setLatestEventInfo(this"uploadservice""請保持程式在後臺執行",  
  6.  pendingintent);  
  7. <span style="color:#ff0000;"> startForeground(0x111, notification);</span>  

注意在onDestroy裡還需要stopForeground(true),執行時在下拉列表會看到自己的APP在:


【結論】如果在極度極度低記憶體的壓力下,該service還是會被kill掉,並且不一定會restart

onDestroy方法裡重啟service

service +broadcast  方式,就是當service走ondestory的時候,傳送一個自定義的廣播,當收到廣播的時候,重新啟動service;

  1. <receiver android:name="com.dbjtech.acbxt.waiqin.BootReceiver" >  
  2.     <intent-filter>  
  3.         <action android:name="android.intent.action.BOOT_COMPLETED" />  
  4.         <action android:name="android.intent.action.USER_PRESENT" />  
  5.         <action android:name="com.dbjtech.waiqin.destroy" />//這個就是自定義的action
  6.     </intent-filter>  
  7. </receiver>  
在onDestroy時:
  1. @Override
  2. publicvoid onDestroy() {  
  3.     stopForeground(true);  
  4.     Intent intent = new Intent("com.dbjtech.waiqin.destroy");  
  5.     sendBroadcast(intent);  
  6.     super.onDestroy();  
  7. }  
在BootReceiver裡
  1. publicclass BootReceiver extends BroadcastReceiver {  
  2.     @Override
  3.     publicvoid onReceive(Context context, Intent intent) {  
  4.         if (intent.getAction().equals("com.dbjtech.waiqin.destroy")) {  
  5.             //TODO
  6.             //在這裡寫重新啟動service的相關操作
  7.                 startUploadService(context);  
  8.         }  
  9.     }  
  10. }  

也可以直接在onDestroy()裡startService

  1. @Override
  2. publicvoid onDestroy() {  
  3.      Intent sevice = new Intent(this, MainService.class);  
  4.      this.startService(sevice);  
  5.     super.onDestroy();  
  6. }  

【結論】當使用類似口口管家等第三方應用或是在setting裡-應用-強制停止時,APP程序可能就直接被幹掉了,onDestroy方法都進不來,所以還是無法保證~.~


Application加上Persistent屬性

看Android的文件知道,當程序長期不活動,或系統需要資源時,會自動清理門戶,殺死一些Service,和不可見的Activity等所在的程序。但是如果某個程序不想被殺死(如資料快取程序,或狀態監控程序,或遠端服務程序),可以這麼做:

  1. <application  
  2.     android:name="com.test.Application"
  3.     android:allowBackup="true"
  4.     android:icon="@drawable/ic_launcher"
  5.     android:label="@string/app_name"
  6.    <span style="color:#ff0000;"> android:persistent="true"</span>  
  7.     android:theme="@style/AppTheme" >  
  8. </application>  

【結論】據說這個屬性不能亂設定,不過設定後,的確發現優先順序提高不少,或許是相當於系統級的程序,但是還是無法保證存活

監聽系統廣播判斷Service狀態

通過系統的一些廣播,比如:手機重啟、介面喚醒、應用狀態改變等等監聽並捕獲到,然後判斷我們的Service是否還存活,別忘記加許可權啊。

  1. <receiver android:name="com.dbjtech.acbxt.waiqin.BootReceiver" >  
  2.     <intent-filter>  
  3.         <action android:name="android.intent.action.BOOT_COMPLETED" />  
  4.         <action android:name="android.intent.action.USER_PRESENT" />  
  5.         <action android:name="android.intent.action.PACKAGE_RESTARTED" />  
  6.         <action android:name="com.dbjtech.waiqin.destroy" />  
  7.     </intent-filter>  
  8. </receiver>  
BroadcastReceiver中:
  1. @Override
  2. publicvoid onReceive(Context context, Intent intent) {  
  3.     if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {  
  4.         System.out.println("手機開機了....");  
  5.         startUploadService(context);  
  6.     }  
  7. 相關推薦

    [轉] Android開發如何保證Service殺掉broadcast+system/app

    轉發:原文連結http://blog.csdn.net/mad1989/article/details/22492519 序言 最近專案要實現這樣一個效果:執行後,要有一個service始終保持在後臺執行,不管使用者作出什麼操作,都要保證service不被kill,這可真是一個難題。參考了現今各種定製版的系

    Android開發如何保證Service殺掉broadcast+system/app

    序言 最近專案要實現這樣一個效果:執行後,要有一個service始終保持在後臺執行,不管使用者作出什麼操作,都要保證service不被kill,這可真是一個難題。參考了現今各種定製版的系統和安全廠商牛虻軟體,如何能保證自己的Service不被殺死呢?

    Android保證service殺掉-增強版: 程序保活(根據使用者需求慎用)

    作者:騰訊——張興華 目前市面上的應用,貌似除了微信和手Q都會比較擔心被使用者或者系統(廠商)殺死問題。本文對 Android 程序拉活進行一個總結。 Android 程序拉活包括兩個層面: A. 提供程序優先順序,降低程序被殺死的概率 B. 在程序被殺死後,進行

    Android Service 殺掉方法broadcast+system/app

    Service簡介 service是在一段不定的時間執行在後臺,不和使用者互動應用元件。每個Service必須在manifest中 通過<service>來宣告。可以通過contect.startservice和contect.bindserverice來啟動。

    andorid如何保證service殺死精簡版

    Android 程序不死從3個層面入手:        A.提供程序優先順序,降低程序被殺死的概率          方法一:監控手機鎖屏解鎖事件,在螢幕鎖屏時啟動1個畫素的 Activity,在使

    Android開發監聽軟鍵盤狀態彈出收回

    概述 如何使用 隱患 概述 在我們開發過程中,有時需要監聽手機軟鍵盤狀態,但是Android沒有這樣的API,所以需要我們自己處理。 實現方案 實現效果與原理 先上一張效果圖 可以看到我們準確的監聽到了軟鍵盤的彈出與收起事

    Android 開發Service 探索如何保證Service殺死或kill之後自動重啟

    前言: 在我司專案1.0版本的時候訊息是使用的環信、用了之後發現各種bug,各種機型不支援導致app崩潰,於是在2.0版本果斷去掉環信,使用了公眾號用的那套訊息系統(老大自己寫的)並做了擴充套件升級。

    保證ServiceKill的解決方案

    req som .html ppp 真機測試 其中 清理工具 reat 清理 1、Service設置成START_STICKY(onStartCommand方法中),kill 後會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣 2、通過 startForegro

    Service啟動方式,如何保證Service殺死,程序等級,IntentService

    一、Service 類的啟動 ,有兩種方法:       •Context.startService()        • Context.bindService()      1. 在同一個應用任何地方呼叫startService() 方法就能啟動 Service

    android開發:保持程序殺死類似微信QQ那種

    從網路上整理的資料,不是個人見解,後續如果有新的發現,我會繼續追蹤。 1Service設定成START_STICKY,kill 後會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣 2​通過 startForeground將程序設定為前臺程序,做前

    C# 影象居中縮放自動裁剪保證影象壓扁或變長

    /// <summary> /// 居中縮放影象 /// </summary> /// <param name="src">源</param> /// &

    Java——Web開發開源的資料庫連線池C3P0與DBCP的使用

    緊接上一篇資料庫連線池的學習,點連線直達~   資料庫連線池的簡單理解與使用 資料庫連線池DBCP程式碼連線與配置檔案: 1.先匯入使用的jar檔案,分別是dbcp.jar與pool.jar檔案 2.分別使用兩種方式實現,使用配置檔案(dbcpconfig.

    android servicekill的方法

    private ActivityManager activityManager; activityManager = (ActivityManager) mcontext.getSystemService(Context.ACTIVITY_SERVICE); IntentFilter

    Android開發Service與IntentService的區別與使用場景

    Service Service 是長期執行在後臺的應用程式元件。 Service 不是一個單獨的程序,它和應用程式在同一個程序中,Service 也不是一個執行緒,它和執行緒沒有任何關係,所以它不能直接處理耗時操作。如果直接把耗時操作放在 Service 的 onStartCommand() 中,

    Android開發魅族手機收到極光推送JPush通知

    情景 收不到通知,狀態列沒有、聲音沒有、控制檯不列印log 如果是控制檯不列印log,那就找MyReceiver找到推送的程式碼部分,檢視編譯是否有問題,有問題的話是肯定不通過的。而且日誌也顯示不出來。 正常的收到推送的話會出來兩條訊息,一條是系統通知,一

    Android開發getX,getRawX,getWidth,getTranslationX等的區別

    save string hlist getwidth sta 是我 touch 項目 寬度 轉載請註明出處:http://blog.csdn.net/dmk877/article/details/51550031 好久沒寫博客了,最近工作確實挺忙的,剛剛結束了一個

    Android 開發Windows環境下Android Studio安裝和使用教程(圖文詳細步驟)

    9.png 虛擬機 jdk版本 編寫 clip 開發平臺 集成開發 arc 電腦安裝 鑒於谷歌最新推出的Android Studio備受開發者的推崇,所以也跟著體驗一下。 一、介紹Android Studio Android Studio 是一個Android

    Android開發AudioManager音頻管理器具體解釋

    應該 數量 service eth out 開發 要求 type 路由 AudioManager簡單介紹: AudioManager類提供了訪問音量和振鈴器mode控制。使用Context.getSystemService(Context.AUDIO_SERVICE)

    【入門篇】ANDROID開發BUG專講

    world 自然 執行 類型 效率 str 積累 全部 href 話說諸葛亮是一個優秀的程序員,每個錦囊都是應對不同的case而編寫的。可是優秀的程序員也敵只是更優秀的bug。六出祈山。七進中原,鞠躬盡瘁,死而後已的諸葛亮僅僅由於有一

    android開發merge結合include優化布局

    ted com match clas you title example ews 文件的 merge結合include優化android布局,效果不知道。個人感覺使用上也有非常大的局限。只是還是了解一下。記錄下來。 布局文件都要有根節點,但androi