Android Service的兩種啓動方式

參考連接html

1. 概念java

開始,先稍稍講一點android中Service的概念和用途吧~android

Service分爲本地服務(LocalService)和遠程服務(RemoteService)服務器

一、本地服務依附在主進程上而不是獨立的進程,這樣在必定程度上節約了資源,另外Local服務由於是在同一進程所以不須要IPC,網絡

也不須要AIDL。相應bindService會方便不少。主進程被Kill後,服務便會終止。app

二、遠程服務爲獨立的進程,對應進程名格式爲所在包名加上你指定的android:process字符串。因爲是獨立的進程,所以在Activity所在進程被Kill的時候,該服務依然在運行,dom

不受其餘進程影響,有利於爲多個進程提供服務具備較高的靈活性。該服務是獨立的進程,會佔用必定資源,而且使用AIDL進行IPC稍微麻煩一點。異步

按使用方式能夠分爲如下三種:ide

一、startService 啓動的服務:主要用於啓動一個服務執行後臺任務,不進行通訊。中止服務使用stopService;函數

二、bindService 啓動的服務:該方法啓動的服務能夠進行通訊。中止服務使用unbindService;

三、startService 同時也 bindService 啓動的服務:中止服務應同時使用stepService與unbindService

2. Service 與 Thread 的區別

不少時候,你可能會問,爲何要用 Service,而不用 Thread 呢,由於用 Thread 是很方便的,比起 Service 也方便多了,下面我詳細的來解釋一下。

1). Thread:Thread 是程序執行的最小單元,它是分配CPU的基本單位。能夠用 Thread 來執行一些異步的操做。

2). Service:Service 是android的一種機制,當它運行的時候若是是Local Service,那麼對應的 Service 是運行在主進程的 main 線程上的。如:onCreate,onStart 這些函數在被系統調用的時候都是在主進程的 main 線程上運行的。若是是RemoteService,那麼對應的 Service 則是運行在獨立進程的 main 線程上。所以請不要把 Service 理解成線程,它跟線程半毛錢的關係都沒有!

既然這樣,那麼咱們爲何要用 Service 呢?其實這跟 android 的系統機制有關,咱們先拿 Thread 來講。Thread 的運行是獨立於 Activity 的,也就是說當一個 Activity 被 finish 以後,若是你沒有主動中止 Thread 或者 Thread 裏的 run 方法沒有執行完畢的話,Thread 也會一直執行。所以這裏會出現一個問題:當 Activity 被 finish 以後,你再也不持有該 Thread 的引用。另外一方面,你沒有辦法在不一樣的 Activity 中對同一 Thread 進行控制。

舉個例子:若是你的 Thread 須要不停地隔一段時間就要鏈接服務器作某種同步的話,該 Thread 須要在 Activity 沒有start的時候也在運行。這個時候當你 start 一個 Activity 就沒有辦法在該 Activity 裏面控制以前建立的 Thread。所以你便須要建立並啓動一個 Service ,在 Service 裏面建立、運行並控制該 Thread,這樣便解決了該問題(由於任何 Activity 均可以控制同一 Service,而系統也只會建立一個對應 Service 的實例)。

所以你能夠把 Service 想象成一種消息服務,而你能夠在任何有 Context 的地方調用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,來控制它,你也能夠在 Service 裏註冊 BroadcastReceiver,在其餘地方經過發送 broadcast 來控制它,固然這些都是 Thread 作不到的。

3.  Service和Activity通訊

       須要用到bindService,經過onBind()方法來實現,看下面bindService的例子

4. Service的生命週期


第一種方式:經過StartService啓動Service

經過startService啓動後,service會一直無限期運行下去,只有外部調用了stopService()或stopSelf()方法時,該Service纔會中止運行並銷燬。

要建立一個這樣的Service,你須要讓該類繼承Service類,而後重寫如下方法:

  • onCreate()
    1.若是service沒被建立過,調用startService()後會執行onCreate()回調;
    2.若是service已處於運行中,調用startService()不會執行onCreate()方法。
    也就是說,onCreate()只會在第一次建立service時候調用,屢次執行startService()不會重複調用onCreate(),此方法適合完成一些初始化工做。

  • onStartCommand()
    若是屢次執行了Context的startService()方法,那麼Service的onStartCommand()方法也會相應的屢次調用。onStartCommand()方法很重要,咱們在該方法中根據傳入的Intent參數進行實際的操做,好比會在此處建立一個線程用於下載數據或播放音樂等。

  • onBind()
    Service中的onBind()方法是抽象方法,Service類自己就是抽象類,因此onBind()方法是必須重寫的,即便咱們用不到。

  • onDestory()
    在銷燬的時候會執行Service該方法。

這幾個方法都是回調方法,且在主線程中執行,由android操做系統在合適的時機調用。

startService代碼實例

建立TestOneService,並在manifest裏註冊。

須要注意,項目中的每個Service都必須在AndroidManifest.xml中註冊才行,因此還須要編輯AndroidManifest.xml文件,代碼以下所示:

 1 <?xml version="1.0" encoding="utf-8"?>  
 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
 3  package="com.example.servicetest"  
 4  android:versionCode="1"  
 5  android:versionName="1.0" >  
 6   
 7     <uses-sdk  8         android:minSdkVersion="14"  
 9  android:targetSdkVersion="17" />  
10   
11     <application 12         android:allowBackup="true"  
13  android:icon="@drawable/ic_launcher"  
14  android:label="@string/app_name"  
15  android:theme="@style/AppTheme" >  
16           
17  …… 18   
19         <service android:name="com.example.servicetest.TestOneService" >  
20         </service>  
21     </application>  
22   
23 </manifest>

在MainActivty中操做TestOneService,code以下:

 1 /**  2  * Created by Kathy on 17-2-6.  3  */  4  
 5 public class TestOneService extends Service{  6  
 7  @Override  8  public void onCreate() {  9  Log.i("Kathy","onCreate - Thread ID = " + Thread.currentThread().getId()); 10  super.onCreate(); 11  } 12  
13  @Override 14  public int onStartCommand(Intent intent, int flags, int startId) { 15  Log.i("Kathy", "onStartCommand - startId = " + startId + ", Thread ID = " + Thread.currentThread().getId()); 16  return super.onStartCommand(intent, flags, startId); 17  } 18  
19  @Nullable 20  @Override 21  public IBinder onBind(Intent intent) { 22  Log.i("Kathy", "onBind - Thread ID = " + Thread.currentThread().getId()); 23  return null; 24  } 25  
26  @Override 27  public void onDestroy() { 28  Log.i("Kathy", "onDestroy - Thread ID = " + Thread.currentThread().getId()); 29  super.onDestroy(); 30  } 31 }

在MainActivity中三次startService,以後stopService。

 1 /**  2  * Created by Kathy on 17-2-6.  3  */  4  
 5 public class MainActivity extends AppCompatActivity {  6  
 7  @Override  8  protected void onCreate(Bundle savedInstanceState) {  9  super.onCreate(savedInstanceState); 10  setContentView(R.layout.activity_main); 11  Log.i("Kathy", "Thread ID = " + Thread.currentThread().getId()); 12  Log.i("Kathy", "before StartService"); 13  
14  //連續啓動Service 15  Intent intentOne = new Intent(this, TestOneService.class); 16  startService(intentOne); 17  Intent intentTwo = new Intent(this, TestOneService.class); 18  startService(intentTwo); 19  Intent intentThree = new Intent(this, TestOneService.class); 20  startService(intentThree); 21  
22  //中止Service 23  Intent intentFour = new Intent(this, TestOneService.class); 24  stopService(intentFour); 25  
26  //再次啓動Service 27  Intent intentFive = new Intent(this, TestOneService.class); 28  startService(intentFive); 29  
30  Log.i("Kathy", "after StartService"); 31  } 32 }

打印出的Log以下:

02-06 15:19:45.090 8938-8938/? I/Kathy: Thread ID = 1
        02-06 15:19:45.090 8938-8938/? I/Kathy: before StartService
        02-06 15:19:45.233 8938-8938/? I/Kathy: onCreate - Thread ID = 1
        02-06 15:19:45.234 8938-8938/? I/Kathy: onStartCommand - startId = 1, Thread ID = 1
        02-06 15:19:45.234 8938-8938/? I/Kathy: onStartCommand - startId = 2, Thread ID = 1
        02-06 15:19:45.235 8938-8938/? I/Kathy: onStartCommand - startId = 3, Thread ID = 1
        02-06 15:19:45.236 8938-8938/? I/Kathy: onDestroy - Thread ID = 1
        02-06 15:19:45.237 8938-8938/? I/Kathy: onCreate - Thread ID = 1
        02-06 15:19:45.237 8938-8938/? I/Kathy: onStartCommand - startId = 1, Thread ID = 1
        02-06 15:19:45.238 8938-8938/? I/Kathy: after StartService

 分析:
1.主線程打印出是1,全部回調方法中打印出的執行線程ID都是1,證實回調方法都是在主線程中執行的
2.三次調用startService,只觸發一次onCreate回調,觸發了三次onStartCommand回調,且startId分別爲1,2,3。證實 屢次startService不會重複執行onCreate回調,但每次都會執行onStartCommand回調

第二種方式:經過bindService啓動Service

bindService啓動服務特色:
1.bindService啓動的服務和調用者之間是典型的client-server模式。調用者是client,service則是server端。service只有一個,但綁定到service上面的client能夠有一個或不少個。這裏所提到的client指的是組件,好比某個Activity。
2.client能夠經過IBinder接口獲取Service實例,從而實如今client端直接調用Service中的方法以實現靈活交互,這在經過startService方法啓動中是沒法實現的。
3.bindService啓動服務的生命週期與其綁定的client息息相關。當client銷燬時,client會自動與Service解除綁定。固然,client也能夠明確調用Context的unbindService()方法與Service解除綁定。當沒有任何client與Service綁定時,Service會自行銷燬

bindService代碼實例

交互界面設計以下:


ActivityA界面佈局.png

ActivityB界面佈局.png

1.建立一個TestTwoService繼承Service(Server)
2.建立ActivityA,能夠經過bindService綁定服務(client)
3.建立ActivityB,能夠經過bindService綁定服務(client)
4.ActivityA能夠跳轉到ActivityB

TestTwoService建立以下:
要想讓Service支持bindService調用方式,須要作如下事情:
1.在Service的onBind()方法中返回IBinder類型的實例。
2.onBInd()方法返回的IBinder的實例須要可以返回Service實例自己。一般,最簡單的方法就是在service中建立binder的內部類,加入相似getService()的方法返回Service,這樣綁定的client就能夠經過getService()方法得到Service實例了。

 1 /**
 2  * Created by Kathy on 17-2-6.  3  */
 4  
 5 public class TestTwoService extends Service{  6  
 7     //client 能夠經過Binder獲取Service實例
 8     public class MyBinder extends Binder {  9         public TestTwoService getService() { 10             return TestTwoService.this; 11  } 12  } 13  
14     //經過binder實現調用者client與Service之間的通訊
15     private MyBinder binder = new MyBinder(); 16  
17     private final Random generator = new Random(); 18  
19  @Override 20     public void onCreate() { 21         Log.i("Kathy","TestTwoService - onCreate - Thread = " + Thread.currentThread().getName()); 22         super.onCreate(); 23  } 24  
25  @Override 26     public int onStartCommand(Intent intent, int flags, int startId) { 27         Log.i("Kathy", "TestTwoService - onStartCommand - startId = " + startId + ", Thread = " + Thread.currentThread().getName()); 28         return START_NOT_STICKY; 29  } 30  
31  @Nullable 32  @Override 33     public IBinder onBind(Intent intent) { 34         Log.i("Kathy", "TestTwoService - onBind - Thread = " + Thread.currentThread().getName()); 35         return binder; 36  } 37  
38  @Override 39     public boolean onUnbind(Intent intent) { 40         Log.i("Kathy", "TestTwoService - onUnbind - from = " + intent.getStringExtra("from")); 41         return false; 42  } 43  
44  @Override 45     public void onDestroy() { 46         Log.i("Kathy", "TestTwoService - onDestroy - Thread = " + Thread.currentThread().getName()); 47         super.onDestroy(); 48  } 49  
50     //getRandomNumber是Service暴露出去供client調用的公共方法
51     public int getRandomNumber() { 52         return generator.nextInt(); 53  } 54 }

client端要作的事情:
1.建立ServiceConnection類型實例,並重寫onServiceConnected()方法和onServiceDisconnected()方法。
2.當執行到onServiceConnected回調時,可經過IBinder實例獲得Service實例對象,這樣可實現client與Service的鏈接。
3.onServiceDisconnected回調被執行時,表示client與Service斷開鏈接,在此能夠寫一些斷開鏈接後須要作的處理。

建立ActivityA,代碼以下:

 1 /**
 2  * Created by Kathy on 17-2-6.  3  */
 4 public class ActivityA extends Activity implements Button.OnClickListener {  5     private TestTwoService service = null;  6     private boolean isBind = false;  7  
 8     private ServiceConnection conn = new ServiceConnection() {  9  @Override 10         public void onServiceConnected(ComponentName name, IBinder binder) { 11             isBind = true; 12             TestTwoService.MyBinder myBinder = (TestTwoService.MyBinder) binder; 13             service = myBinder.getService(); 14             Log.i("Kathy", "ActivityA - onServiceConnected"); 15             int num = service.getRandomNumber(); 16             Log.i("Kathy", "ActivityA - getRandomNumber = " + num); 17  } 18  
19  @Override 20         public void onServiceDisconnected(ComponentName name) { 21             isBind = false; 22             Log.i("Kathy", "ActivityA - onServiceDisconnected"); 23  } 24  }; 25  
26     protected void onCreate(Bundle savedInstanceState) { 27         super.onCreate(savedInstanceState); 28  setContentView(R.layout.activity_a); 29         Log.i("Kathy", "ActivityA - onCreate - Thread = " + Thread.currentThread().getName()); 30  
31         findViewById(R.id.btnBindService).setOnClickListener(this); 32         findViewById(R.id.btnUnbindService).setOnClickListener(this); 33         findViewById(R.id.btnStartActivityB).setOnClickListener(this); 34         findViewById(R.id.btnFinish).setOnClickListener(this); 35  } 36  
37  @Override 38     public void onClick(View v) { 39         if (v.getId() == R.id.btnBindService) { 40             //單擊了「bindService」按鈕
41             Intent intent = new Intent(this, TestTwoService.class); 42             intent.putExtra("from", "ActivityA"); 43             Log.i("Kathy", "----------------------------------------------------------------------"); 44             Log.i("Kathy", "ActivityA 執行 bindService"); 45  bindService(intent, conn, BIND_AUTO_CREATE); 46         } else if (v.getId() == R.id.btnUnbindService) { 47             //單擊了「unbindService」按鈕
48             if (isBind) { 49                 Log.i("Kathy", 50                         "----------------------------------------------------------------------"); 51                 Log.i("Kathy", "ActivityA 執行 unbindService"); 52  unbindService(conn); 53  } 54         } else if (v.getId() == R.id.btnStartActivityB) { 55             //單擊了「start ActivityB」按鈕
56             Intent intent = new Intent(this, ActivityB.class); 57             Log.i("Kathy", 58                     "----------------------------------------------------------------------"); 59             Log.i("Kathy", "ActivityA 啓動 ActivityB"); 60  startActivity(intent); 61         } else if (v.getId() == R.id.btnFinish) { 62             //單擊了「Finish」按鈕
63             Log.i("Kathy", 64                     "----------------------------------------------------------------------"); 65             Log.i("Kathy", "ActivityA 執行 finish"); 66             this.finish(); 67  } 68  } 69  
70  @Override 71     protected void onDestroy() { 72         super.onDestroy(); 73         Log.i("Kathy", "ActivityA - onDestroy"); 74  } 75 }

建立ActivityB,代碼以下:

 1 /**
 2  * Created by Kathy on 17-2-6.  3  */
 4 public class ActivityB extends Activity implements Button.OnClickListener {  5  
 6     private TestTwoService service = null;  7  
 8     private boolean isBind = false;  9  
10     private ServiceConnection conn = new ServiceConnection() { 11  @Override 12         public void onServiceConnected(ComponentName name, IBinder binder) { 13             isBind = true; 14             TestTwoService.MyBinder myBinder = (TestTwoService.MyBinder)binder; 15             service = myBinder.getService(); 16             Log.i("Kathy", "ActivityB - onServiceConnected"); 17             int num = service.getRandomNumber(); 18             Log.i("Kathy", "ActivityB - getRandomNumber = " + num); 19  } 20  
21  @Override 22         public void onServiceDisconnected(ComponentName name) { 23             isBind = false; 24             Log.i("Kathy", "ActivityB - onServiceDisconnected"); 25  } 26  }; 27  
28  @Override 29     protected void onCreate(Bundle savedInstanceState) { 30         super.onCreate(savedInstanceState); 31  setContentView(R.layout.activity_b); 32  
33         findViewById(R.id.btnBindService).setOnClickListener(this); 34         findViewById(R.id.btnUnbindService).setOnClickListener(this); 35         findViewById(R.id.btnFinish).setOnClickListener(this); 36  } 37  
38  @Override 39     public void onClick(View v) { 40         if(v.getId() == R.id.btnBindService){ 41             //單擊了「bindService」按鈕
42             Intent intent = new Intent(this, TestTwoService.class); 43             intent.putExtra("from", "ActivityB"); 44             Log.i("Kathy", "----------------------------------------------------------------------"); 45             Log.i("Kathy", "ActivityB 執行 bindService"); 46  bindService(intent, conn, BIND_AUTO_CREATE); 47         }else if(v.getId() == R.id.btnUnbindService){ 48             //單擊了「unbindService」按鈕
49             if(isBind){ 50                 Log.i("Kathy", "----------------------------------------------------------------------"); 51                 Log.i("Kathy", "ActivityB 執行 unbindService"); 52  unbindService(conn); 53  } 54         }else if(v.getId() == R.id.btnFinish){ 55             //單擊了「Finish」按鈕
56             Log.i("Kathy", "----------------------------------------------------------------------"); 57             Log.i("Kathy", "ActivityB 執行 finish"); 58             this.finish(); 59  } 60  } 61  @Override 62     public void onDestroy(){ 63         super.onDestroy(); 64         Log.i("Kathy", "ActivityB - onDestroy"); 65  } 66 }

測試步驟1

step1: 點擊ActivityA的bindService按鈕
step2: 再點擊ActivityA的unbindService按鈕
Log輸出:

 1 02-07 14:09:38.031 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA - onCreate - Thread = main  2 02-07 14:09:39.488 1738-1738/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
 3 02-07 14:09:39.488 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA 執行 bindService  4 02-07 14:09:39.496 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onCreate - Thread = main  5 02-07 14:09:39.497 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onBind - Thread = main  6 02-07 14:09:39.500 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA - onServiceConnected  7 02-07 14:09:39.500 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA - getRandomNumber = -1046987376
 8 02-07 14:09:50.866 1738-1738/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
 9 02-07 14:09:50.866 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA 執行 unbindService 10 02-07 14:09:50.870 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onUnbind - from = ActivityA 11 02-07 14:09:50.871 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onDestroy - Thread = main

總結調用bindService以後發生的事情:
1.client執行bindService()
2.若是Service不存在,則Service執行onCreate(),onBind()
3.client實例ServiceConnection執行onServiceConnected()方法

總結調用unbindService以後發生的事情:
1.client執行unbindService()
2.client與Service解除綁定鏈接狀態
3.Service檢測是否還有其餘client與其鏈接,若是沒有Service執行onUnbind()和onDestroy()

測試步驟2

step1: 點擊ActivityA的bindService按鈕
step2: 再點擊ActivityA的Finish按鈕
Log 輸出:

02-07 14:49:16.626 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onCreate - Thread = main
02-07 14:49:18.102 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:49:18.102 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 執行 bindService
02-07 14:49:18.105 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onCreate - Thread = main
02-07 14:49:18.110 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onBind - Thread = main
02-07 14:49:18.112 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onServiceConnected
02-07 14:49:18.112 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - getRandomNumber = -318399886
02-07 14:49:19.540 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:49:19.540 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 執行 finish
02-07 14:49:19.789 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onDestroy
02-07 14:49:19.798 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onUnbind - from = ActivityA
02-07 14:49:19.798 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onDestroy - Thread = main

 

總結:若是client銷燬,那麼client會自動與Service解除綁定。

測試步驟3

step1: 點擊ActivityA的bindService按鈕
step2: 點擊ActivityA的startActivity B按鈕,切換到ActivityB
step3: 點擊ActivityB中的bindService按鈕
step4: 點擊ActivityB中的unbindService按鈕
step5: 點擊ActivityB中的Finish按鈕
step6: 點擊ActivityA中的unbindService按鈕
獲得Log:

02-07 14:55:04.390 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onCreate - Thread = main
02-07 14:55:08.191 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:08.191 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 執行 bindService
02-07 14:55:08.197 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onCreate - Thread = main
02-07 14:55:08.198 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onBind - Thread = main
02-07 14:55:08.205 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onServiceConnected
02-07 14:55:08.205 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - getRandomNumber = -706215542
02-07 14:55:23.261 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:23.261 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 啓動 ActivityB
02-07 14:55:29.239 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:29.239 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB 執行 bindService
02-07 14:55:29.241 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB - onServiceConnected
02-07 14:55:29.241 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB - getRandomNumber = 1827572726
02-07 14:55:33.951 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:33.951 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB 執行 unbindService
02-07 14:55:36.645 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:36.645 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB 執行 finish
02-07 14:55:36.852 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB - onDestroy
02-07 14:55:43.137 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:43.137 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 執行 unbindService
02-07 14:55:43.143 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onUnbind - from = ActivityA
02-07 14:55:43.143 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onDestroy - Thread = main

 

總結bindService的生命週期:
1.點擊ActivityA的bindService按鈕
第一次調用bindService會實例化TestTwoService,而後執行其onBind()方法,獲得IBinder類型的實例,將其做爲參數傳入ActivityA的ServiceConnection的onServiceConnected方法中,標誌着ActivityA與TestTwoService創建了綁定

2.點擊ActivityB中的bindService按鈕
因爲TestTwoService已處於運行狀態,因此再次調用bindService不會從新建立它的實例,因此也不會執行TestTwoService的onCreate()方法和onBind()方法。ActivityB與ActivityA共享IBinder實例。此時有兩個client與TestTwoService綁定

3.點擊ActivityB中的unbindService按鈕
ActivityB與TestTwoService解除了綁定,當沒有任何client與Service綁定時,纔會執行Service的onUnbind()方法。此時,ActivityA還在綁定鏈接中,因此不會執行Service的解綁方法

4.點擊ActivityA中的unbindService按鈕
ActivityA執行unbindService以後,ActivityA與TestTwoService就解除綁定了,這樣就沒有client與TestTwoService綁定,這時候Android會銷燬TestTwoService,在銷燬前會先執行TestTwoService的onUnbind()方法,而後纔會執行其onDestroy()方法,這樣TestService就銷燬了。

如何保證Service不被殺死?

1. onStartCommand方式中,返回START_STICKY

首先咱們來看看onStartCommand均可以返回哪些值:

調用Context.startService方式啓動Service時,若是Android面臨內存匱乏,可能會銷燬當前運行的Service,待內存充足時能夠重建Service。而Service被Android系統強制銷燬並再次重建的行爲依賴於Service的onStartCommand()方法的返回值。

  • START_NOT_STICKY
    若是返回START_NOT_STICKY,表示當Service運行的進程被Android系統強制殺掉以後,不會從新建立該Service
    。固然若是在其被殺掉以後一段時間又調用了startService,那麼該Service又將被實例化。那什麼情境下返回該值比較恰當呢?
    若是咱們某個Service執行的工做被中斷幾回可有可無或者對Android內存緊張的狀況下須要被殺掉且不會當即從新建立這種行爲也可接受,那麼咱們即可將 onStartCommand的返回值設置爲START_NOT_STICKY。
    舉個例子,某個Service須要定時從服務器獲取最新數據:經過一個定時器每隔指定的N分鐘讓定時器啓動Service去獲取服務端的最新數據。當執行到Service的onStartCommand時,在該方法內再規劃一個N分鐘後的定時器用於再次啓動該Service並開闢一個新的線程去執行網絡操做。假設Service在從服務器獲取最新數據的過程當中被Android系統強制殺掉,Service不會再從新建立,這也不要緊,由於再過N分鐘定時器就會再次啓動該Service並從新獲取數據。

  • START_STICKY
    若是返回START_STICKY,表示Service運行的進程被Android系統強制殺掉以後,Android系統會將該Service依然設置爲started狀態(即運行狀態),可是再也不保存onStartCommand方法傳入的intent對象,而後Android系統會嘗試再次從新建立該Service,並執行onStartCommand回調方法,可是onStartCommand回調方法的Intent參數爲null,也就是onStartCommand方法雖然會執行可是獲取不到intent信息。若是你的Service能夠在任意時刻運行或結束都沒什麼問題,並且不須要intent信息,那麼就能夠在onStartCommand方法中返回START_STICKY,好比一個用來播放背景音樂功能的Service就適合返回該值。

  • START_REDELIVER_INTENT
    若是返回START_REDELIVER_INTENT,表示Service運行的進程被Android系統強制殺掉以後,與返回START_STICKY的狀況相似,Android系統會將再次從新建立該Service,並執行onStartCommand回調方法,可是不一樣的是,Android系統會再次將Service在被殺掉以前最後一次傳入onStartCommand方法中的Intent再次保留下來並再次傳入到從新建立後的Service的onStartCommand方法中,這樣咱們就能讀取到intent參數。只要返回START_REDELIVER_INTENT,那麼onStartCommand重的intent必定不是null。若是咱們的Service須要依賴具體的Intent才能運行(須要從Intent中讀取相關數據信息等),而且在強制銷燬後有必要從新建立運行,那麼這樣的Service就適合返回START_REDELIVER_INTENT。

2.提升Service的優先級
在AndroidManifest.xml文件中對於intent-filter能夠經過android:priority = "1000"這個屬性設置最高優先級,1000是最高值,若是數字越小則優先級越低,同時適用於廣播。

3.提高Service進程的優先級

當系統進程空間緊張時,會依照優先級自動進行進程的回收。
Android將進程分爲6個等級,按照優先級由高到低依次爲:

  • 前臺進程foreground_app
  • 可視進程visible_app
  • 次要服務進程secondary_server
  • 後臺進程hiddena_app
  • 內容供應節點content_provider
  • 空進程empty_app
    可使用startForeground將service放到前臺狀態,這樣低內存時,被殺死的機率會低一些。

4.在onDestroy方法裏重啓Service
當service走到onDestroy()時,發送一個自定義廣播,當收到廣播時,從新啓動service。

5.系統廣播監聽Service狀態
6.將APK安裝到/system/app,變身爲系統級應用




FROM: 

Android Service兩種啓動方式詳解(總結版)

http://www.jianshu.com/p/4c798c91a613

 

Android Service徹底解析,關於服務你所需知道的一切(上)

http://blog.csdn.net/guolin_blog/article/details/11952435/

 

Android中Service的使用詳解和注意點(LocalService)

http://www.cnblogs.com/linlf03/p/3296323.html

 

Android四大組件:Service服務史上最全面解析

http://www.jianshu.com/p/d963c55c3ab9

相關文章
相關標籤/搜索