1. 程式人生 > >Android 學習之Service

Android 學習之Service

什麼是Service?

       Service,俗名服務。在Android系統中,Service與Activity就像一個媽生的,不僅長得像,而且行為(生命週期)也有一些類似。對於Activity來說大家肯定不會陌生,開發Android應用中打過交道最多的莫非就是Activity了,所以今天我們藉助Activity來引入講解Service。Service跟Activity一樣是Android的四大元件之一,需要在AndroidManifest清單檔案中進行註冊。Service不像Activity在前臺執行,而且是與之呼應進行後臺執行的服務;如果把Activity當成下載軟體的使用者互動介面,而Service就是那個默默在後臺執行的下載執行緒,所以Service的應用場景就是那些我們不需要它常駐前臺但需要它一直在後臺工作的時候,例如下載、播放音樂、IM軟體監聽客戶端訊息等。


如何啟動Service?

      啟動Service有兩種方式,不單調且奢華。在元件中我們可以用類似於Activity的啟動方式的startService()來啟動Service,用stopService()來關閉啟動的服務;當然也可以用比較獨特的繫結啟動方式bindService()來啟動Service這個服務,對應的解綁方法自然就是unbindService()。當然這兩種啟動方式的不同也意味著Service有著不一樣的生命週期呼叫方法。

例:

定義一個Service類

public class MyService extends Service {

//onBind為必須實現的抽象方法

@Override

public IBinder onBind(Intent intent) {

return new MyBinder();

}

@Override

public void onCreate() {

super.onCreate();

}

@Override

public void onDestroy() {

super.onDestroy();

}

@Override

public void onRebind(Intent intent) {

super.onRebind(intent);

}

@Override

public void onStart(Intent intent, int startId) {

super.onStart(intent, startId);

}

@Override

public boolean onUnbind(Intent intent) {

return super.onUnbind(intent);

}

/**

* 構造一個MyBinder類,其繼承於Binder,而Binder實現了IBinder的介面

*/

public class MyBinder extends Binder{

//返回Service例項的引用

public MyService getId(){

return MyService.this;

}

}

}

啟動方式為startService:

//啟動一個Service 

Intent intent =newIntent(this, MyService.class);

startService(intent);

//停止Service

stopService(intent);

startService()啟動方式的生命週期為:

context.startService() -> onCreate() -> onStart() -> Service 執行中 -> context.stop() -> onDestroy() -> Service 被關閉

啟動方式為bindService:

private class MyServiceConnection implements ServiceConnection{

public MyServiceConnection(){}

@Override

public void onServiceConnected(ComponentName arg0, IBinder binder) {

MyService Myservice = ((MyService.MyBinder)binder).getService();

//繫結成功後呼叫

}

@Override

public void onServiceDisconnected(ComponentName arg0) {

//當服務奔潰時呼叫

}

}

然後進行bind啟動Service

//繫結一個Service

Intent intent =newIntent(this, MyService.class);

MyServiceConnection conn=newMyServiceConnection();

bindService(intent, conn, Context.BIND_AUTO_CREATE);

//解綁Service

unbindService(conn);

當我們執行bindService()後,系統將會呼叫onCreate()和onBind(),而在onBind()執行完畢後,將會回撥ServiceConnection中的onServiceConnected()的方法,同時傳回一個實現了IBinder介面的類(一般會選擇傳回繼承至Binder的子類,因為Binder實現了IBinder的介面),然後我們可以通過某些手段(參考上面程式碼)從IBinder中獲取Service的例項。

bindService()啟動方式生命週期:

context.bindService() -> onCreate() -> onBind() -> Service 執行中 -> context.unBindService() -> onUnbind() -> onDestroy() -> Service被關閉



某些特殊情況:

情形一:當我們在元件中呼叫startService()了來啟動Service,但是我們並沒有呼叫stopService()來銷燬這個服務,那麼我們在再次startService()來啟動這個服務的時候,並沒有呼叫onCreate()這個回撥方法,而是僅僅執行了onStart()。為什麼呢?因為在Android系統,每個服務都被設定成單例模式,無論呼叫多少次startService()來啟動Service,在系統永遠只會執行一個Service。而onCreate()是Service被建立時被呼叫的,所以在多次重複啟動Service不會呼叫onCreate(),因為此時系統中已經存在Service這個服務了,所以只會呼叫onStart()。也就是說在多次啟動服務時,onCreate()只會被呼叫一次,而onStart()可以被呼叫多次。

情形二:當我們需要把通過startService()啟動的Service掃地出門的時候,呼叫stopService()就能滿足我們小小的要求,這時候程式一般如我們預料的執行onDestroy()。但是如果我們並沒有祭出stopService()這把寶劍,而是把呼叫者(如Activity)直接kill掉,那麼會執行onDestroy()這個方法嗎?答案是不會的,因為自從啟動了Service後,該服務就跟呼叫者撇清關係了,不論呼叫者生老病死都跟他沒半毛錢關係,除非打出stopService()通過意圖(intent)把服務回收,當然這一切是建立在該Service是通過startService的方式啟動的前提上。

情形三:現在說一下繫結服務(bindService)的情況,同startService的方式一樣,如果多次重複啟動Service,onCreate()依然只會呼叫建立Service服務的那個第一次。而對於onBind()則會在每次重複繫結服務的時候被呼叫,請示在這裡onBind()最主要的作用就是將Ibinder傳回到繫結者,借用其建立繫結者與Service的聯絡。而如果有多個繫結的存在,那麼執行unbindService()僅僅只會觸發onUnbind()而不會觸發onDestroy(),只有最後一個繫結者呼叫unbindService()才會觸發服務的onDestroy()的呼叫。還有一個特別的地方就是,如果銷燬繫結者(例如Activity),那麼繫結的這個Service會隨他而去(執行onUnbid->onDestroy)。



寫在最後


1、如果你需要一個在呼叫者退出後仍然不會被銷燬,但同時需要獲取他的引用,那麼有這麼一個小方法。先startService()啟動服務,然後bindService繫結該服務,此時可以獲取到Service的引用,然後在解綁unbindService,由於先startService所以只會執行onUnbind(),這時由於沒有繫結關係,就算該呼叫者掛掉了,Service依然執行如舊。

2、Service雖然說是後臺執行,但是實際上說它仍然是執行在主執行緒,這裡說得執行在主執行緒是其onCreate、onStart、onBind等生命週期方法執行在主執行緒,如果這些方法進行諸如下載、讀取大檔案等耗時工作,會引起主執行緒的阻塞;所以我們一般會在Service中另起子執行緒執行我們需要的業務。

3、Service的啟動、繫結和停止、解綁應該在對應的呼叫者相應的生命週期中,例如需要Service貫穿整個Activity,我們可以再onCreate中啟動、繫結Service、在onDestroy中停止或解綁Service。如果只是需要在使用者前臺時執行服務,那麼應該在onStart和onStop中進行相應的處理。不建議在onPause和onResume中對於服務進行啟動停止的操作,因為這樣會可能造成不必要的效能消耗,舉個例子,當兩個activity同時需要這個服務,那麼在前個activity的onPause剛結束服務時,下個activity在onResume馬上啟動該服務,造成一些噁心的問題。

4、有人認為為什麼在bindService的時候不把Ibinder返回到呼叫者那裡,這個是因為啟動服務時非同步的,在呼叫bindService的時候是無法獲取IBinder並返回的,所以只能在後面通過呼叫onbind的時候把IBinder扔到onServiceConnected的引數裡面。

5、有些人會碰到onServiceConnected()在bindService後並沒有被呼叫,請檢查你的onBind()函式,如果返回值為null是不會觸發onServiceConnected()的回撥的,所以我們要確保onBind返回的是一個實現了IBinder介面的類。

6、我們可以在onUnbind()方法中返回true,這樣的話,在我們解綁Service後再次繫結該Service,將會呼叫onRebind()這個不怎麼常見的回撥方法,而不會去執行onBind()。