Android開發之如何保證Service不被殺掉(前台服務)


序言

    最近項目要實現這樣一個效果:運行后,要有一個service始終保持在后台運行,不管用戶作出什么操作,都要保證service不被kill。參考了現今各種定制版的系統和安全廠商牛虻軟件,如何能保證自己的Service不被殺死呢?其實除了常規的手段,我們可以參考一下微信和360,設置-程序-正在運行,可以看到微信是同時開啟了兩個進程和服務:

  

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如果要防止盡可能不被系統殺掉,需要設置為在前台運行。

1.MainActivity.java

 1 package com.example.helloteacher;
 2 
 3 import com.example.teacherService.HelloteacherService;
 4 import com.example.teacherService.HelloteacherService2;
 5 
 6 import android.app.Activity;
 7 import android.content.Intent;
 8 import android.os.Bundle;
 9 import android.util.Log;
10 import android.view.View;
11 import android.widget.Button;
12 import android.widget.TextView;
13 
14 public class MainActivity extends Activity {
15     private TextView fuction;
16     private Button start;
17     @Override
18     protected void onCreate(Bundle savedInstanceState) {
19         super.onCreate(savedInstanceState);
20         setContentView(R.layout.activity_main);
21         //初始化控件
22         init();
23         //創建進程
24         inProcess();
25 }
26     ///初始化控件函數
27     private void init() {
28         start=(Button)findViewById(R.id.button1);
29         fuction=(TextView)findViewById(R.id.tv_bottom_funtion);
30         start.setOnClickListener(new StartOnClickListener());
31         fuction.setOnClickListener(new FuctionOnClickListener());
32     }
33     //功能按鈕監聽實現函數
34     private final class  FuctionOnClickListener implements View.OnClickListener{
35 
36         @Override
37         public void onClick(View v) {
38             // TODO Auto-generated method stub
39             Intent intent = new Intent(MainActivity.this, FuctionActivity.class);
40             startActivity(intent);
41         }
42     }
43     //進程函數
44     private void inProcess(){
45         Intent intent =new Intent(MainActivity.this, HelloteacherService.class);
46         startService(intent);  
47         Intent intent2 =new Intent(MainActivity.this, HelloteacherService2.class);
48         startService(intent2);
49     }
50     private final class  StartOnClickListener implements View.OnClickListener{
51 
52         @Override
53         public void onClick(View v) {
54              
55         }
56     }
57     
58     
59 }

2.HelloteacherService.java

 1 package com.example.teacherService;
 2 
 3 import com.example.Receiver.Alarmreceiver;
 4 import com.example.helloteacher.R;
 5 
 6 import android.app.AlarmManager;
 7 import android.app.Notification;
 8 import android.app.PendingIntent;
 9 import android.app.Service;
10 import android.content.Intent;
11 import android.os.IBinder;
12 import android.os.SystemClock;
13 import android.util.Log;
14 
15 public class HelloteacherService extends Service {
16     HelloteacherService2 hs2;
17     private String TAG="HelloteacherService";
18     @Override
19     public void onCreate() {
20         super.onCreate();
21        Log.i(TAG, "-->>onCreate");
22     }
23     
24     @Override
25     public int onStartCommand(Intent intent, int flags, int startId) {
26         Log.i(TAG, "-->>onStartCommand-->>"+startId);
27          flags = START_STICKY;  
28          
29          //啟用前台服務,主要是startForeground()
30             Notification notification = new Notification(R.drawable.ic_launcher, "用電腦時間過長了!白痴!"
31                     , System.currentTimeMillis());
32             notification.setLatestEventInfo(this, "快去休息!!!",
33                     "一定保護眼睛,不然遺傳給孩子,老婆跟別人跑啊。", null);
34             //設置通知默認效果
35             notification.flags = Notification.FLAG_SHOW_LIGHTS;
36             startForeground(1, notification);
37 
38             AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
39             //讀者可以修改此處的Minutes從而改變提醒間隔時間
40             //此處是設置每隔55分鍾啟動一次
41             //這是55分鍾的毫秒數
42             int Minutes = 55 * 60 * 1000;
43             //SystemClock.elapsedRealtime()表示1970年1月1日0點至今所經歷的時間
44             long triggerAtTime = SystemClock.elapsedRealtime() + Minutes;
45             //此處設置開啟AlarmReceiver這個Service
46             Intent i = new Intent(this, Alarmreceiver.class);
47             PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
48             //ELAPSED_REALTIME_WAKEUP表示讓定時任務的出發時間從系統開機算起,並且會喚醒CPU。
49             manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
50          
51         return super.onStartCommand(intent, flags, startId);
52     }
53    //監聽服務2實現函數
54    
55     
56     @Override
57     public IBinder onBind(Intent arg0) {
58         Log.i(TAG, "-->>onBind");
59         // TODO Auto-generated method stub
60         return null;
61     }
62      @Override
63      public void onDestroy() {
64          Log.i(TAG, "-->>onDestroy");
65             super.onDestroy();
66 
67         }
68 }

3.BootReceiver.java

 1 package com.example.Receiver;
 2 
 3 import android.app.AlarmManager;
 4 import android.app.PendingIntent;
 5 import android.content.BroadcastReceiver;
 6 import android.content.Context;
 7 import android.content.Intent;
 8 import android.os.SystemClock;
 9 
10 public class BootReceiver extends BroadcastReceiver {
11 
12     /*要接收的intent源*/
13     static final String ACTION = "android.intent.action.BOOT_COMPLETED";
14         
15     public void onReceive(Context context, Intent mintent) 
16     {
17         if (Intent.ACTION_BOOT_COMPLETED.equals(mintent.getAction())) {  
18             // 啟動完成  
19             Intent intent = new Intent(context, Alarmreceiver.class);  
20             intent.setAction("arui.alarm.action");  
21             PendingIntent sender = PendingIntent.getBroadcast(context, 0,  
22                     intent, 0);  
23             long firstime = SystemClock.elapsedRealtime();  
24             AlarmManager am = (AlarmManager) context  
25                     .getSystemService(Context.ALARM_SERVICE);  
26   
27             // 10秒一個周期,不停的發送廣播  
28             am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstime,  
29                     10 * 1000, sender);  
30         }  
31     }
32 
33 
34 }

4.Alarmreceiver.java

 1 package com.example.Receiver;
 2 
 3 import com.example.teacherService.HelloteacherService;
 4 
 5 import android.content.BroadcastReceiver;
 6 import android.content.Context;
 7 import android.content.Intent;
 8 
 9 public class Alarmreceiver extends BroadcastReceiver {
10 
11     @Override
12     public void onReceive(Context context, Intent intent) {
13         // TODO Auto-generated method stub
14         if (intent.getAction().equals("arui.alarm.action")) {  
15             Intent i = new Intent();  
16             i.setClass(context, HelloteacherService.class);  
17             // 啟動service   
18             // 多次調用startService並不會啟動多個service 而是會多次調用onStart  
19             context.startService(i);  
20         }  
21     }
22 
23 }

5.配置文件

AndroidManifest.xml

下面是添加在配置文件中的部分代碼:

 1  <activity android:name="com.example.helloteacher.FuctionActivity" />
 2         <service android:name="com.example.teacherService.HelloteacherService" android:process=":HelloteacherService"/>
 3         <service android:name="com.example.teacherService.HelloteacherService2"/>
 4         <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
 5      <receiver android:name="com.example.Receiver.BootReceiver" > 
 6     <intent-filter> 
 7        <action android:name="android.intent.action.BOOT_COMPLETED" /> 
 8     </intent-filter> 
 9     </receiver>
10     <receiver  android:name="com.example.Receiver.Alarmreceiver" >  
11     <intent-filter>  
12         <action android:name="arui.alarm.action" />  
13     </intent-filter>  
14 </receiver>  

通過以上的配置,就可以實現Service的前台運行!下面附上效果圖:


免責聲明!

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



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