Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> 【Android Service】3、bindService和remoteService介紹

【Android Service】3、bindService和remoteService介紹

編輯:Android開發實例

 一、bindService簡介

 

bindService是綁定Service服務,執行service服務中的邏輯流程。

service通過Context.startService()方法開始,通過Context.stopService()方法停止;也可以通過Service.stopSelf()方法或者Service.stopSelfResult()方法來停止自己。只要調用一次stopService()方法便可以停止服務,無論之前它被調用了多少次的啟動服務方法。

 

客戶端建立一個與Service的鏈接,並使用此鏈接與Service進行通話,通過Context.bindService()方法來綁定服務,Context.unbindService()方法來關閉服務。多個客戶端可以綁定同一個服務,如果Service還未被啟動,bindService()方法可以啟動服務。

 

上面startService()和bindService()兩種模式是完全獨立的。你可以綁定一個已經通過startService()方法啟動的服務。例如:一個後台播放音樂服務可以通過startService(intend)對象來播放音樂。可能用戶在播放過程中要執行一些操作比如獲取歌曲的一些信息,此時activity可以通過調用bindServices()方法與Service建立連接。這種情況下,stopServices()方法實際上不會停止服務,直到最後一次綁定關閉。

 

二、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在一個生命周期中只能被調用一次。詳見:http://www.fengfly.com/plus/view-210582-1.html

 

三、bindService生命周期

 

像一個activity那樣,一個service有些可以用來改變狀態的生命周期方法,但是比activity的方法少,service生命周期方法只有三個public

   void onCreate()

   void onStart(Intent intent)

   void onDestroy()

通過實現這三個生命周期方法,你可以監聽service的兩個嵌套循環的生命周期:

1、整個生命周期

 service的整個生命周期是在onCreate()和onDestroy()方法之間。和activity一樣,在onCreate()方法裡初始化,在onDestroy()方法裡釋放資源。例如,一個背景音樂播放服務可以在onCreate()方法裡播放,在onDestroy()方法裡停止。

 

2、活動的生命周期

 service的活動生命周期是在onStart()之後,這個發法會處理通過startServices()方法傳遞來的Intent對象。音樂service可以通過開打intent對象來找到要播放的音樂,然後開始後台播放。注: service停止時沒有相應的回調方法,即沒有onStop()方法。

 

onCreate()方法和onDestroy()方法是針對所有的services,無論它們是否啟動,通過Context.startService()和Context.bindService()方法都可以訪問執行。然而,只有通過startService()方法啟動service服務時才會調用onStart()方法。

 

如果一個service允許別人綁定,那麼需要實現以下額外的方法:

       IBinder onBind(Intent intent)

       boolean onUnbind(Intent intent)

       void onRebind(Intent intent)

onBind()回調方法會繼續傳遞通過bindService()傳遞來的intent對像

onUnbind()會處理傳遞給unbindService()的intent對象。如果service允許綁定,onBind()會返回客戶端與服務互相聯系的通信句柄(實例)。

如果建立了一個新的客戶端與服務的鏈接,onUnbind()方法可以請求調用onRebind()方法。

 

記住任何服務,無論它怎樣建立,都默認客戶端可以鏈接,所以任何的service能夠接收onBind()和onUnbind()方法

 

四、bindService示例

Activity

 

  1. public class PlayBindMusic extends Activity implements OnClickListener { 
  2.  
  3.     private Button playBtn; 
  4.     private Button stopBtn; 
  5.     private Button pauseBtn; 
  6.     private Button exitBtn; 
  7.  
  8.     private BindMusicService musicService; 
  9.  
  10.     @Override 
  11.     public void onCreate(Bundle savedInstanceState) { 
  12.         super.onCreate(savedInstanceState); 
  13.  
  14.         setContentView(R.layout.bind_music_service); 
  15.  
  16.         playBtn = (Button) findViewById(R.id.play); 
  17.         stopBtn = (Button) findViewById(R.id.stop); 
  18.         pauseBtn = (Button) findViewById(R.id.pause); 
  19.         exitBtn = (Button) findViewById(R.id.exit); 
  20.  
  21.         playBtn.setOnClickListener(this); 
  22.         stopBtn.setOnClickListener(this); 
  23.         pauseBtn.setOnClickListener(this); 
  24.         exitBtn.setOnClickListener(this); 
  25.  
  26.         connection(); 
  27.     } 
  28.  
  29.     private void connection() { 
  30.         Intent intent = new Intent("com.homer.bind.bindService"); 
  31.         bindService(intent, sc, Context.BIND_AUTO_CREATE);          // bindService 
  32.     } 
  33.  
  34.     @Override 
  35.     public void onClick(View v) { 
  36.         switch (v.getId()) { 
  37.         case R.id.play: 
  38.             musicService.play(); 
  39.             break; 
  40.         case R.id.stop: 
  41.             if (musicService != null) { 
  42.                 musicService.stop(); 
  43.             } 
  44.             break; 
  45.         case R.id.pause: 
  46.             if (musicService != null) { 
  47.                 musicService.pause(); 
  48.             } 
  49.             break; 
  50.         case R.id.exit: 
  51.             this.finish(); 
  52.             break; 
  53.         } 
  54.     } 
  55.  
  56.     private ServiceConnection sc = new ServiceConnection() { 
  57.  
  58.         @Override 
  59.         public void onServiceConnected(ComponentName name, IBinder service) {       //connect Service 
  60.             musicService = ((BindMusicService.MyBinder) (service)).getService(); 
  61.             if (musicService != null) { 
  62.                 musicService.play();        // play music 
  63.             } 
  64.         } 
  65.          
  66.         @Override 
  67.         public void onServiceDisconnected(ComponentName name) {                 //disconnect Service 
  68.             musicService = null; 
  69.         } 
  70.     }; 
  71.      
  72.     @Override 
  73.     public void onDestroy(){ 
  74.         super.onDestroy(); 
  75.          
  76.         if(sc != null){ 
  77.             unbindService(sc); 
  78.         } 
  79.     } 

 

Service

 

  1. public class BindMusicService extends Service { 
  2.  
  3.     private MediaPlayer mediaPlayer; 
  4.  
  5.     private final IBinder binder = new MyBinder(); 
  6.  
  7.     public class MyBinder extends Binder { 
  8.         BindMusicService getService() { 
  9.             return BindMusicService.this; 
  10.         } 
  11.     } 
  12.  
  13.     @Override 
  14.     public IBinder onBind(Intent intent) { 
  15.         return binder; 
  16.     } 
  17.  
  18.     @Override 
  19.     public void onCreate() { 
  20.         super.onCreate(); 
  21.          
  22.         Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show(); 
  23.     } 
  24.  
  25.     @Override 
  26.     public void onDestroy() { 
  27.         super.onDestroy(); 
  28.          
  29.         Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT); 
  30.         if(mediaPlayer != null){ 
  31.             mediaPlayer.stop(); 
  32.             mediaPlayer.release(); 
  33.         } 
  34.     } 
  35.  
  36.      
  37.     public void play() { 
  38.         if (mediaPlayer == null) { 
  39.             mediaPlayer = MediaPlayer.create(this, R.raw.tmp); 
  40.             mediaPlayer.setLooping(false); 
  41.         } 
  42.         if (!mediaPlayer.isPlaying()) { 
  43.             mediaPlayer.start(); 
  44.         } 
  45.     } 
  46.  
  47.     public void pause() { 
  48.         if (mediaPlayer != null && mediaPlayer.isPlaying()) { 
  49.             mediaPlayer.pause(); 
  50.         } 
  51.     } 
  52.  
  53.     public void stop() { 
  54.         if (mediaPlayer != null) { 
  55.             mediaPlayer.stop(); 
  56.             try { 
  57.                 mediaPlayer.prepare();      // 在調用stop後如果需要再次通過start進行播放,需要之前調用prepare函數 
  58.             } catch (IOException ex) { 
  59.                 ex.printStackTrace(); 
  60.             } 
  61.         } 
  62.     } 

AndroidManifest.xml

 

  1. <service 
  2.     android:name=".bind.BindMusicService" 
  3.     android:enabled="true" > 
  4.     <intent-filter> 
  5.         <action android:name="com.homer.bind.bindService" /> 
  6.     </intent-filter> 
  7. </service> 

 

五、代碼解析

1、 Activity中,Intent intent = new Intent("com.homer.bind.bindService"); 構建一個service的action,然後bindService(intent, sc, Context.BIND_AUTO_CREATE); 綁定服務

2、 Activity中,通過private ServiceConnection sc = new ServiceConnection() 建立一個Service連接,onServiceConnected()獲取Service實例,onServiceDisconnected()釋放連接

3、 Service中,重載onBind(Intent intent)方法,返回Service實例(即BindMusicService)給Activity,然後執行onCreate()函數(注:bindService不執行onStart()函數)

4、 Activity中,通過返回的Service實例musicService,執行音樂播放的操作(play、pause、stop等)

 

六、Remote Service拓展

通常每個應用程序都在它自己的進程內運行,但有時需要在進程之間傳遞對象(IPC通信),你可以通過應用程序UI的方式寫個運行在一個不同的進程中的service。在android平台中,一個進程通常不能訪問其它進程中的內存區域。所以,他們需要把對象拆分成操作系統能理解的簡單形式,以便偽裝成對象跨越邊界訪問。編寫這種偽裝代碼相當的枯燥乏味,好在android為我們提供了AIDL工具可以來做這件事。
 
AIDL(android接口描述語言)是一個IDL語言,它可以生成一段代碼,可以使在一個android設備上運行的兩個進程使用內部通信進程進行交互。如果你需要在一個進程中(例如在一個Activity中)訪問另一個進程中(例如一個Service)某個對象的方法,你就可以使用AIDL來生成這樣的代碼來偽裝傳遞各種參數。
 
要使用AIDL,Service需要以aidl文件的方式提供服務接口,AIDL工具將生成一個相應的java接口,並且在生成的服務接口中包含一個功能調用的stub服務樁類。Service的實現類需要去繼承這個stub服務樁類。Service的onBind方法會返回實現類的對象,之後你就可以使用它了,參見下例:

IMusicControlService.aidl

 

  1. package com.homer.remote; 
  2.  
  3. interface IMusicControlService{ 
  4.         void play();  
  5.         void stop();  
  6.         void pause(); 

 

 

使用eclipse的Android插件,會根據這個aidl文件生成一個Java接口類,生成的接口類中會有一個內部類Stub類,Service來繼承該Stub類: Service  
  1. public class RemoteMusicService extends Service { 
  2.  
  3.     private MediaPlayer mediaPlayer; 
  4.  
  5.     @Override 
  6.     public IBinder onBind(Intent intent) { 
  7.         return binder; 
  8.     } 
  9.  
  10.     private final IMusicControlService.Stub binder = new IMusicControlService.Stub() { 
  11.  
  12.         @Override 
  13.         public void play() throws RemoteException { 
  14.             if (mediaPlayer == null) { 
  15.                 mediaPlayer = MediaPlayer.create(RemoteMusicService.this, R.raw.tmp); 
  16.                 mediaPlayer.setLooping(false); 
  17.             } 
  18.             if (!mediaPlayer.isPlaying()) { 
  19.                 mediaPlayer.start(); 
  20.             } 
  21.         } 
  22.  
  23.         @Override 
  24.         public void pause() throws RemoteException { 
  25.             if (mediaPlayer != null && mediaPlayer.isPlaying()) { 
  26.                 mediaPlayer.pause(); 
  27.             }            
  28.         } 
  29.  
  30.         @Override 
  31.         public void stop() throws RemoteException { 
  32.             if (mediaPlayer != null) { 
  33.                 mediaPlayer.stop(); 
  34.                 try { 
  35.                     mediaPlayer.prepare();      // 在調用stop後如果需要再次通過start進行播放,需要之前調用prepare函數 
  36.                 } catch (IOException ex) { 
  37.                     ex.printStackTrace(); 
  38.                 } 
  39.             } 
  40.         } 
  41.     }; 
  42.      
  43.     @Override 
  44.     public void onDestroy() { 
  45.         super.onDestroy(); 
  46.          
  47.         if(mediaPlayer != null){ 
  48.             mediaPlayer.stop(); 
  49.             mediaPlayer.release(); 
  50.         } 
  51.     } 

 

 

客戶端(Activity)應用連接到這個Service時,onServiceConnected方法將被調用,客戶端就可以獲得IBinder對象。參看下面的客戶端onServiceConnected方法:

 

Activity

 

  1. public class PlayRemoteMusic extends Activity implements OnClickListener { 
  2.  
  3.     private Button playBtn; 
  4.     private Button stopBtn; 
  5.     private Button pauseBtn; 
  6.     private Button exitBtn; 
  7.  
  8.     private IMusicControlService musicService; 
  9.  
  10.     @Override 
  11.     public void onCreate(Bundle savedInstanceState) { 
  12.         super.onCreate(savedInstanceState); 
  13.         setContentView(R.layout.remote_music_service); 
  14.  
  15.         playBtn = (Button) findViewById(R.id.play); 
  16.         stopBtn = (Button) findViewById(R.id.stop); 
  17.         pauseBtn = (Button) findViewById(R.id.pause); 
  18.         exitBtn = (Button) findViewById(R.id.exit); 
  19.  
  20.         playBtn.setOnClickListener(this); 
  21.         stopBtn.setOnClickListener(this); 
  22.         pauseBtn.setOnClickListener(this); 
  23.         exitBtn.setOnClickListener(this); 
  24.  
  25.         connection(); 
  26.     } 
  27.  
  28.     private void connection() { 
  29.         Intent intent = new Intent("com.homer.remote.remoteMusicReceiver"); 
  30.         bindService(intent, sc, Context.BIND_AUTO_CREATE);              // bindService 
  31.     } 
  32.  
  33.     @Override 
  34.     public void onClick(View v) { 
  35.  
  36.         try { 
  37.             switch (v.getId()) { 
  38.             case R.id.play: 
  39.                 musicService.play(); 
  40.                 break; 
  41.             case R.id.stop: 
  42.                 if (musicService != null) { 
  43.                     musicService.stop(); 
  44.                 } 
  45.                 break; 
  46.             case R.id.pause: 
  47.                 if (musicService != null) { 
  48.                     musicService.pause(); 
  49.                 } 
  50.                 break; 
  51.             case R.id.exit: 
  52.                 this.finish(); 
  53.                 break; 
  54.             } 
  55.         } catch (RemoteException e) { 
  56.             e.printStackTrace(); 
  57.         } 
  58.     } 
  59.  
  60.     private ServiceConnection sc = new ServiceConnection() { 
  61.         @Override 
  62.         public void onServiceConnected(ComponentName name, IBinder service) {       //connect Service 
  63.             musicService = IMusicControlService.Stub.asInterface(service); 
  64.         } 
  65.  
  66.         @Override 
  67.         public void onServiceDisconnected(ComponentName name) {                 //disconnect Service 
  68.             musicService = null; 
  69.         } 
  70.  
  71.     }; 
  72.      
  73.     @Override 
  74.     public void onDestroy(){ 
  75.         super.onDestroy(); 
  76.          
  77.         if(sc != null){ 
  78.             unbindService(sc);              // unBindService 
  79.         } 
  80.     } 

 

Remote Service流程總結:

1、 Activity(客戶端)中,Intent intent = new Intent("com.homer.remote.remoteMusicReceiver");構建intent,然後bindService(intent, sc, Context.BIND_AUTO_CREATE);綁定服務

2、 Activity(客戶端)中,通過ServiceConnection()重載onServiceConnected()建立連接,獲取Service.Stub實例;onServiceDisconnected()釋放連接(與bindService類似)

3、 Service中,通過重載onBind(Intent intent) 返回Service.Stub實例,但Service.Stub類是由aidl文件生成的接口類中的一個內部類Stub類,Service來繼承該Stub類

4、 Activity中,通過操作Service實例(musicService),執行音樂播放操作(play、pause、stop等)

 

源碼下載

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved