1. 程式人生 > >Android服務類Service詳細解析

Android服務類Service詳細解析

Service有什麼作用?

許多人不明白service是用來幹嘛的,其實Service作為Android四大元件之一,可以理解為一個執行在後臺的Activity,它適用於處理一些不干擾使用者的長時間的後臺操作,比如你播放器播放音樂之後跳到其它頁面,音樂需要繼續播放,那麼這個時候就可以將音樂的播放一直執行在後臺服務中,需要啟動播放的時候就通過Activity去啟動服務,再通過服務去呼叫播放,需要停止的時候就停止服務。

有人可能會問,Thread也可以實現後臺執行,為什麼不用Thread而使用Service呢?

Service和Thread是完全不同的兩個概念,thread是子執行緒,是與主執行緒沒有交集的,而
Service是執行在主執行緒上的,是與主執行緒有交集。當然你會說為什麼服務執行在主執行緒中不會反而影響效能嗎為何還要用它?其實Service作為Android系統元件,是與Activity等立的,我們完全可以在其中定義子執行緒進行後臺操作。如果需要大量的後臺費時資料處理操作,最好的方式是在Service中開子執行緒,而不是直接開一個子執行緒,這樣是為了提高子執行緒的優先順序,而不會輕易被系統殺掉。


Thread是獨立於主執行緒的,即使Activity結束了,假如你沒有主動對它的子執行緒進行關閉,Thread仍有可能還在默默執行著,這個時候,你已經控制不到這些子執行緒了因為你已經把持有該Activity給結束掉了,這樣對於程式很不安全。

舉個例子:如果你的應用是一個聊天的應用,需要建立一個Thread每隔一小段時間就去訪問伺服器並實時顯示有沒有人傳送了訊息給你,那這個時候當你跳轉到別的Activity比如個人設定等頁面,而原來持有該Thread的Activity已經finfish,等你回去的時候已經控制不了你剛才在聊天Activity建立的那個子執行緒了,同樣也就無法正常關閉這些子執行緒了。那麼這個時候就需要service了,因為service是獨立於Activity的,可以在其中建立子執行緒,即使Activity關閉了,也能夠操作管理或者關閉這些子執行緒。而且不Service也不是和Activity一一對應,可以有多個Activity對應一個Service,這些Thread是無法做到的。


Service的使用方法:

原始方式建立服務:
定義一個類為MyService,繼承自Service,並實現其中唯一的抽象方法:onbind(),其用處見下文:

public class MyService extends Service{
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}
}

這樣一個最原始的服務類就建立完成,接下來我們要在Activity中去啟動它(通過intent啟動):

Intent intent = new Intent(MainActivity.this,MyService.class);
startService(intent);

這個時候我跑一下程式,會發現程式崩潰了。報錯:android:content:ActivityNotFoundException:Unable to find exnlicit activity class。問題就在於Service也是Android四大元件之一,必須要在AndroidMainfest.xml檔案中註冊這個服務:


註冊完成之後再執行一遍,便成功啟動服務。
如何停止服務:

Intent intent = new Intent(MainActivity.this,MyService.class);
stopService(intent);


繫結方式建立服務:
以上是通過startService方式啟動服務,這種情況下除非主動關閉,不然即使Activity關閉了,服務依舊可以在後臺一直執行
還有另外一種能夠通過與Activity繫結的服務,這種情況下一旦Activity關閉了,服務也會相應關閉:

這時候就需要呼叫我們一開始說的onBind方法,binder在這個時候就相當於連線點:
在我們自定義的MyService類中,新增一個IBinder物件,並建立一個MyBinder內部類,在裡面定義一個方法能夠獲得當前服務,並且重寫onBind以及onUnBind方法:

public class MyService extends Service{
	
	private final IBinder binder = new MyBinder();  
	
	public class MyBinder extends Binder {  
        	MyService getService() {  
            		return MyService.this;  
        	}  
    	} 

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		Log.d("MyService", "onBind...");
		return binder;
	}

	@Override
	public boolean onUnbind(Intent intent) {
		// TODO Auto-generated method stub
		Log.d("MyService", "onUnBind...");
		return super.onUnbind(intent);
	}
}


這種方式下啟動服務需要通過呼叫onBind方法:

Intent intent = new Intent(MainActivity.this,MyService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);//這裡即繫結並啟動了服務

可以看到有3個引數,第一個即傳入啟動該MyService的intent,第二個傳入的是一個ServiceConnection物件,第三個是呼叫系統的變量表示自動繫結,其中,connection的建立如下:

final ServiceConnection connection = new ServiceConnection() {	
	@Override
	public void onServiceDisconnected(ComponentName arg0) {
		// TODO Auto-generated method stub
		//onServiceDisconnected()方法在正常情況下是不被呼叫的,它的呼叫時機是當Service服務被異外銷燬時		,例如記憶體的資源不足時				
	}
					
	@Override
	public void onServiceConnected(ComponentName arg0, IBinder binder) {
		// TODO Auto-generated method stub
		MyBinder mybinder = (MyBinder)binder;
		MyService myservice = mybinder.getService();  //獲得該服務
		//在這裡獲取有關服務的各種資訊包括狀態等等						
	}
};

停止服務:通過呼叫onUnbind方法,傳入剛才的connection,就會停止服務

上文我們用兩種方式演示瞭如何建立一個初始的Service,但會有疑問:如何檢視Service到底運行了沒有?

public boolean isServiceWork(Context mContext, String serviceName) {  
	boolean isWork = false;  
	ActivityManager myAM = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);  
	List<RunningServiceInfo> myList = myAM.getRunningServices(40);  
	if (myList.size() <= 0) {  
		return false;  
	}  
	for (int i = 0; i < myList.size(); i++) {  
		String mName = myList.get(i).service.getClassName().toString();  
		if (mName.equals(serviceName)) {  
			isWork = true;  
			break;  
		}  
	}  
	return isWork;  
}  

呼叫這個方法,並傳入當前Activity的context,以及服務名:包名+服務的類名(例如:com.example.MyService)
如果結果返回true則表示正在執行,false表示已經關閉。

Service的生命週期:

原始方式的生命週期:
我們可以通過重寫Service中的onCreate、onStartCommand、onDestroy方法並分別列印日誌來進行檢視:

public class MyService extends Service{

	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		Log.d("MyService", "onCreate...");
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		Log.d("MyService", "onStartCommand...");
		return super.onStartCommand(intent, flags, startId);
	}
	
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		Log.d("MyService", "onDestroy...");
	}

}


在佈局檔案中建立兩個按鈕:


程式碼呼叫:

startservice = (Button)this.findViewById(R.id.startservice);
stopservice = (Button)this.findViewById(R.id.stopservice);
startservice.setOnClickListener(new OnClickListener() {
			
	@Override
	public void onClick(View arg0) {
		// TODO Auto-generated method stub
		Intent intent = new Intent(MainActivity.this,MyService.class);
		startService(intent);
	}
});
		
stopservice.setOnClickListener(new OnClickListener() {
			
	@Override
	public void onClick(View arg0) {
		// TODO Auto-generated method stub
		Intent intent = new Intent(MainActivity.this,MyService.class);
		stopService(intent);
	}
});

執行程式,點選啟動服務按鈕,檢視logcat列印:


再點選多幾次啟動服務按鈕:


點選關閉服務按鈕:


可以看出,當我們第一次點選啟動服務時,呼叫了服務的onCreate方法,當我們再點選多次啟動時,只調用服務的onStartCommand方法,點選關閉的時候,呼叫了服務的onDestroy方法。所以我們大概瞭解了服務的生命週期:
1.第一次啟動服務時,呼叫onCreate
2.第二次啟動服務時,不會再呼叫onCreate而是呼叫onStartCommand
3.關閉服務時,呼叫onDestroy銷燬

流程圖如下:


繫結方式的生命週期:
程式碼上文已經講述,這裡不再描述,同理在onBind和onUnBind方法中列印日誌,可得到其執行流程如下:
onCreate --> onBind(只一次,不可多次繫結) --> onUnbind --> onDestory