Service是一個長期運行在後臺,並不提供界面的應用組件。其餘組件能夠啓動一個服務,而且即便用戶切換到其餘的應用,該服務仍可在後臺繼續運行。另外,組件能夠把某個服務邦定到本身,來與其交互通訊,甚至包括執行進程間通訊(IPC)。所以在播放器的開發中,爲了讓播放音樂不依賴於具體的Activity,將播放音樂的控制放於Service中。html
Service和Activity同樣,須要在AndroidMainfest.xml中進行配置,配置以下:android
1 <service 2 android:name="com.porco.service.PlayService" android:exported="false"> 3 <intent-filter> 4 <action android:name="PlayService" /> 5 </intent-filter> 6 </service>
在此處設置了android:exported這個屬性。這是用於指示該服務是否可以被其餘應用程序組件調用或跟它交互:若是設置爲true,則可以被調用或交互,不然不能。設置爲false時,只有同一個應用程序的組件或帶有相同用戶ID的應用程序才能啓動或綁定該服務。
它的默認值依賴與該服務所包含的過濾器。沒有過濾器則意味着該服務只能經過指定明確的類名來調用,這樣就是說該服務只能在應用程序的內部使用(由於其餘外部使用者不會知道該服務的類名),所以這種狀況下,這個屬性的默認值是false。另外一方面,若是至少包含了一個過濾器,則意味着該服務能夠給外部的其餘應用提供服務,所以默認值是true,此種狀況下在Eclipse中會有警告信息:Exported service does not require permission。ide
Service的使用方式有兩種:context.s在tartService() 和 context.bindService()。其生命週期分別是:post
context.startService() 啓動流程:學習
context.startService() -> onCreate() -> onStartCommand() -> Service running -> context.stopService() -> onDestroy() -> Service stop 測試
若是Service尚未運行,則android先調用onCreate(),而後調用onStartCommand();ui
若是Service已經運行,則只調用onStartCommand(),因此一個Service的onStartCommand方法可能會重複調用屢次。 this
若是stopService的時候會直接onDestroy,若是是調用者本身直接退出而沒有調用stopService的話,Service會一直在後臺運行,該Service的調用者再啓動起來後能夠經過stopService關閉Service。url
因此調用startService的生命週期爲:onCreate --> onStart (可屢次調用) --> onDestroyspa
context.bindService()啓動流程:
context.bindService() -> onCreate() -> onBind() -> Service running -> onUnbind() -> onDestroy() -> Service stop
onBind()將返回給客戶端一個IBind接口實例,IBind容許客戶端回調服務的方法,好比獲得Service的實例、運行狀態或其餘操做。這個時候把調用者(Context,例如Activity)會和Service綁定在一塊兒,Context退出了,Srevice就會調用onUnbind->onDestroy相應退出。
因此調用bindService的生命週期爲:onCreate --> onBind(只一次,不可屢次綁定) --> onUnbind --> onDestory。
在Service每一次的開啓關閉過程當中,只有onStart可被屢次調用(經過屢次startService調用),其餘onCreate,onBind,onUnbind,onDestory在一個生命週期中只能被調用一次。
在具體使用時,可分爲如下三種狀況:
1.startService啓動服務。
2.bindService啓動服務。
3.startService & bindService 啓動服務。
爲了測試不一樣狀況下的service的調用及生命週期,編寫測試demo代碼以下:
Activity部分·:
public class PlayActivity extends Activity { private Intent intent=new Intent("tService"); private Button mButtonBind; private Button mButtonUnbind; private Button mButtonplay; private Button mButtonStart; private Button mButtonStop; TestService tService; ServiceConnection conn=new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub Log.d("activity1","service service disconnected"); } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub //System.out.println("bind ok"); Log.d("activity1","service connnected"); tService=((TestService.MBinder) service ).getService(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.player); //bindService(intent, conn, BIND_AUTO_CREATE); mButtonBind=(Button)findViewById(R.id.buttonbind); mButtonUnbind=(Button)findViewById(R.id.buttonunbind); mButtonplay=(Button)findViewById(R.id.buttonserviceplay); mButtonStart=(Button)findViewById(R.id.buttonstart); mButtonStop=(Button)findViewById(R.id.buttonstop); mButtonBind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub bindService(intent, conn, BIND_AUTO_CREATE); Log.d("activity1","activity after bindservice"); } }); mButtonUnbind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub unbindService(conn); Log.d("activity1","activity after unbindservice"); } }); mButtonplay.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub tService.play(); } }); mButtonStart.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub startService(intent); Log.d("activity1","start service"); } }); mButtonStop.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub stopService(intent); Log.d("activity1","stop service"); } }); } }
Service部分:
public class TestService extends Service { private Thread mThread; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub Log.d("service","onbind"); return new MBinder(); } class MBinder extends Binder{ public TestService getService(){ return TestService.this; } } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); Log.d("service","service create"); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.d("service","service destory"); } @Override public boolean onUnbind(Intent intent) { // TODO Auto-generated method stub Log.d("service","service unbind"); return super.onUnbind(intent); } @Override public void onRebind(Intent intent) { // TODO Auto-generated method stub super.onRebind(intent); Log.d("service","service rebind"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.d("service","service start"); return super.onStartCommand(intent, flags, startId); } public void play(){ Log.d("service","service play"); } }
1.startService啓動服務:用於啓動一個服務執行後臺任務,不進行通訊,中止服務使用stopService。點擊按鈕調用startService()方法,輸出結果以下:
2.bindService啓動服務:該方法啓動的服務要進行通訊,中止服務使用unbindService。點擊按鈕調用bindService()方法,輸出結果以下:
3.startService & bindService 啓動服務:Service將會一直在後臺運行,同時調用stopService和unbindService才能中止服務。輸出結果(一種)以下:
綜合以上,能夠得出:
1.在Service未啓動時,不管是調用startService 仍是 bindService 方法,都會先調用service的onCreate()方法建立一個service服務。
2.在Service建立後銷燬前,若是調用startService方法,每調用一次都會觸發一次service的onStartCommand()方法;若是調用bindService方法,若是已綁定,則不會再觸發service的onBind方法。
3.若是要銷燬service,則須要調用對應的方法:startService--stopService ,bindService--unbindService,startService & bindService--stopService &unbindService,纔會觸發service的onDestory方法。
此外,有一點須要注意的是,在執行bindService方法後,下一個語句的執行先於service的建立,所以,須要注意對於binder返回的對象的使用,防止出錯。具體service和activity在同一進程中的運行關係及狀況須要後續學習。
參考文檔:
Android Service 服務(一)—— Service