Android開發之怎樣監聽讓Service不被殺死


一、Service簡單介紹

Service是在一段不定的時間執行在后台,不和用戶交互應用組件。

每一個Service必須在manifest中 通過<service>來聲明。

能夠通過contect.startservice和contect.bindserverice來啟動。和其它的應用組件一樣,執行在進程的主線程中。這就是說假設service須要非常多耗時或者堵塞的操作,須要在其子線程中實現(或者用系統提供的IntentService,它繼承了Service,它處理數據是用自身新開的線程)。


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

它能夠啟動並執行,直至有人停止了它或它自己停止。

在這樣的方式下。它以調用Context.startService()啟動。而以調用Context.stopService()結束。它能夠調用Service.stopSelf() 或 Service.stopSelfResult()來自己停止。不論調用了多少次startService()方法,你僅僅須要調用一次stopService()來停止服務。

用於實現應用程序自己的一些耗時任務。比方查詢升級信息,並不占用應用程序比方Activity所屬線程,而是單開線程后台運行,這樣用戶體驗比較好。

遠程服務 Remote Service 用於android系統內部的應用程序之間。

它能夠通過自定義並暴露出來的接口進行程序操作。client建立一個到服務對象的連接。並通過那個連接來調用服務。連接以調用Context.bindService()方法建立,以調用 Context.unbindService()關閉。

多個client能夠綁定至同一個服務。假設服務此時還沒有載入,bindService()會先載入它。

可被其它應用程序復用。比方天氣預報服務。其它應用程序不須要再寫這種服務,調用已有的就可以。


1。Service的生命周期


2,Service執行方式

以startService()啟動service,系統將通過傳入的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)或者client連接(bindService)到它。

當內存不足時,須要保持。擁有service的進程具有較高的優先級。

1. 假設service正在調用onCreate,onStartCommand或者onDestory方法。那么用於當前service的進程則變為前台進程以避免被killed。


2. 假設當前service已經被啟動(start)。擁有它的進程則比那些用戶可見的進程優先級低一些,可是比那些不可見的進程更重要,這就意味着service一般不會被killed.
3. 假設client已經連接到service (bindService),那么擁有Service的進程則擁有最高的優先級,能夠覺得service是可見的。
4. 假設service能夠使用startForeground(int, Notification)方法來將service設置為前台狀態,那么系統就覺得是對用戶可見的。並不會在內存不足時killed。
假設有其它的應用組件作為Service,Activity等執行在同樣的進程中。那么將會添加該進程的重要性。


二、保證service不死

onStartCommand方法,返回START_STICKY。

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。

[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. @Override  
  2. public int onStartCommand(Intent intent, int flags, int startId) {  
  3.     flags = START_STICKY;  
  4.     return super.onStartCommand(intent, flags, startId);  
  5. }  

【結論】 手動返回START_STICKY。親測當service因內存不足被kill。當內存又有的時候。service又被又一次創建,比較不錯


提升service進程優先級

在AndroidManifest.xml文件里對於intent-filter能夠通過android:priority = "1000"這個屬性設置最高優先級,1000是最高值,假設數字越小則優先級越低,同一時候有用於廣播

[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  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>  


提升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 API將service放到前台狀態。這樣在低內存時被kill的幾率更低。可是假設在極度極度低內存的壓力下,該service還是會被kill掉。


在onStartCommand方法內

[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1.  Notification notification = new Notification(R.drawable.ic_launcher,  
  2.  getString(R.string.app_name), System.currentTimeMillis());  
  3.   
  4.  PendingIntent pendingintent = PendingIntent.getActivity(this0,  
  5.                    new Intent(this, AppMain.class), 0);  
  6.  notification.setLatestEventInfo(this"uploadservice""請保持程序在后台執行",  
  7.  pendingintent);  
  8.  startForeground(0x111, notification);
注意在onDestroy里還須要stopForeground(true);


在onDestroy方法里重新啟動service

service +broadcast  方式,就是當service走ondestory的時候,發送一個自己定義的廣播。當收到廣播的時候。又一次啟動service;

[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  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時:

[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. @Override  
  2. public void onDestroy() {  
  3.     stopForeground(true);  
  4.     Intent intent = new Intent("com.dbjtech.waiqin.destroy");  
  5.     sendBroadcast(intent);  
  6.     super.onDestroy();  
  7. }  
在BootReceiver里

[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. public class BootReceiver extends BroadcastReceiver {  
  2.   
  3.     @Override  
  4.     public void onReceive(Context context, Intent intent) {  
  5.         if (intent.getAction().equals("com.dbjtech.waiqin.destroy")) {  
  6.             //TODO  
  7.             //在這里寫又一次啟動service的相關操作  
  8.                 startUploadService(context);  
  9.         }  
  10.   
  11.     }  
  12.   
  13. }  
【結論】當然,你也能夠在onDestroy里直接startService(),我通過使用broadcast,能夠做很多其它的處理推斷操作。


一個不被殺死的進程

看Android的文檔知道,當進程長期不活動。或系統須要資源時,會自己主動清理門戶,殺死一些Service,和不可見的Activity等所在的進程。

可是假設某個進程不想被殺死(如數據緩存進程,或狀態監控進程。或遠程服務進程),能夠這么做:

[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  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.     android:persistent="true"
  7.     android:theme="@style/AppTheme" >  
  8. </application>  
【結論】據說這個屬性不能亂設置,只是設置后,的確發現優先級提高不少,也許是相當於系統級的進程。


系統各種廣播監聽

通過系統的廣播,監聽並捕獲到。然后推斷是否須要又一次啟動service。

[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />  // 開機啟動
[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  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" />  
  6.     </intent-filter>  
  7. </receiver>  
[java]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. @Override  
  2. public void onReceive(Context context, Intent intent) {  
  3.     if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {  
  4.         System.out.println("手機開機了....");  
  5.         startUploadService(context);  
  6.     }  
  7.     if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {  
  8.             startUploadService(context);  
  9.     }  
  10. }  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM