Android Service 服務(三)—— bindService與remoteService

來源:互聯網
上載者:User

一、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在一個生命週期中只能被調用一次。詳見:Android Service 服務(一)—— Service

三、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

public class PlayBindMusic extends Activity implements OnClickListener {</p><p>private Button playBtn;<br />private Button stopBtn;<br />private Button pauseBtn;<br />private Button exitBtn;</p><p>private BindMusicService musicService;</p><p>@Override<br />public void onCreate(Bundle savedInstanceState) {<br />super.onCreate(savedInstanceState);</p><p>setContentView(R.layout.bind_music_service);</p><p>playBtn = (Button) findViewById(R.id.play);<br />stopBtn = (Button) findViewById(R.id.stop);<br />pauseBtn = (Button) findViewById(R.id.pause);<br />exitBtn = (Button) findViewById(R.id.exit);</p><p>playBtn.setOnClickListener(this);<br />stopBtn.setOnClickListener(this);<br />pauseBtn.setOnClickListener(this);<br />exitBtn.setOnClickListener(this);</p><p>connection();<br />}</p><p>private void connection() {<br />Intent intent = new Intent("com.homer.bind.bindService");<br />bindService(intent, sc, Context.BIND_AUTO_CREATE);// bindService<br />}</p><p>@Override<br />public void onClick(View v) {<br />switch (v.getId()) {<br />case R.id.play:<br />musicService.play();<br />break;<br />case R.id.stop:<br />if (musicService != null) {<br />musicService.stop();<br />}<br />break;<br />case R.id.pause:<br />if (musicService != null) {<br />musicService.pause();<br />}<br />break;<br />case R.id.exit:<br />this.finish();<br />break;<br />}<br />}</p><p>private ServiceConnection sc = new ServiceConnection() {</p><p>@Override<br />public void onServiceConnected(ComponentName name, IBinder service) {//connect Service<br />musicService = ((BindMusicService.MyBinder) (service)).getService();<br />if (musicService != null) {<br />musicService.play();// play music<br />}<br />}</p><p>@Override<br />public void onServiceDisconnected(ComponentName name) {//disconnect Service<br />musicService = null;<br />}<br />};</p><p>@Override<br />public void onDestroy(){<br />super.onDestroy();</p><p>if(sc != null){<br />unbindService(sc);<br />}<br />}<br />}
Service

public class BindMusicService extends Service {</p><p>private MediaPlayer mediaPlayer;</p><p>private final IBinder binder = new MyBinder();</p><p>public class MyBinder extends Binder {<br />BindMusicService getService() {<br />return BindMusicService.this;<br />}<br />}</p><p>@Override<br />public IBinder onBind(Intent intent) {<br />return binder;<br />}</p><p>@Override<br />public void onCreate() {<br />super.onCreate();</p><p>Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show();<br />}</p><p>@Override<br />public void onDestroy() {<br />super.onDestroy();</p><p>Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT);<br />if(mediaPlayer != null){<br />mediaPlayer.stop();<br />mediaPlayer.release();<br />}<br />}</p><p>public void play() {<br />if (mediaPlayer == null) {<br />mediaPlayer = MediaPlayer.create(this, R.raw.tmp);<br />mediaPlayer.setLooping(false);<br />}<br />if (!mediaPlayer.isPlaying()) {<br />mediaPlayer.start();<br />}<br />}</p><p>public void pause() {<br />if (mediaPlayer != null && mediaPlayer.isPlaying()) {<br />mediaPlayer.pause();<br />}<br />}</p><p>public void stop() {<br />if (mediaPlayer != null) {<br />mediaPlayer.stop();<br />try {<br />mediaPlayer.prepare();// 在調用stop後如果需要再次通過start進行播放,需要之前調用prepare函數<br />} catch (IOException ex) {<br />ex.printStackTrace();<br />}<br />}<br />}<br />}
AndroidManifest.xml

<service<br /> android:name=".bind.BindMusicService"<br /> android:enabled="true" ><br /> <intent-filter><br /> <action android:name="com.homer.bind.bindService" /><br /> </intent-filter><br /> </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

package com.homer.remote;</p><p>interface IMusicControlService{<br /> void play();<br /> void stop();<br /> void pause();<br />}使用eclipse的Android外掛程式,會根據這個aidl檔案產生一個Java介面類,產生的介面類中會有一個內部類Stub類,Service來繼承該Stub類:Servicepublic class RemoteMusicService extends Service {</p><p>private MediaPlayer mediaPlayer;</p><p>@Override<br />public IBinder onBind(Intent intent) {<br />return binder;<br />}</p><p>private final IMusicControlService.Stub binder = new IMusicControlService.Stub() {</p><p>@Override<br />public void play() throws RemoteException {<br />if (mediaPlayer == null) {<br />mediaPlayer = MediaPlayer.create(RemoteMusicService.this, R.raw.tmp);<br />mediaPlayer.setLooping(false);<br />}<br />if (!mediaPlayer.isPlaying()) {<br />mediaPlayer.start();<br />}<br />}</p><p>@Override<br />public void pause() throws RemoteException {<br />if (mediaPlayer != null && mediaPlayer.isPlaying()) {<br />mediaPlayer.pause();<br />}<br />}</p><p>@Override<br />public void stop() throws RemoteException {<br />if (mediaPlayer != null) {<br />mediaPlayer.stop();<br />try {<br />mediaPlayer.prepare();// 在調用stop後如果需要再次通過start進行播放,需要之前調用prepare函數<br />} catch (IOException ex) {<br />ex.printStackTrace();<br />}<br />}<br />}<br />};</p><p>@Override<br />public void onDestroy() {<br />super.onDestroy();</p><p>if(mediaPlayer != null){<br />mediaPlayer.stop();<br />mediaPlayer.release();<br />}<br />}<br />}
用戶端(Activity)應用串連到這個Service時,onServiceConnected方法將被調用,用戶端就可以獲得IBinder對象。參看下面的用戶端onServiceConnected方法:

Activity

public class PlayRemoteMusic extends Activity implements OnClickListener {</p><p>private Button playBtn;<br />private Button stopBtn;<br />private Button pauseBtn;<br />private Button exitBtn;</p><p>private IMusicControlService musicService;</p><p>@Override<br />public void onCreate(Bundle savedInstanceState) {<br />super.onCreate(savedInstanceState);<br />setContentView(R.layout.remote_music_service);</p><p>playBtn = (Button) findViewById(R.id.play);<br />stopBtn = (Button) findViewById(R.id.stop);<br />pauseBtn = (Button) findViewById(R.id.pause);<br />exitBtn = (Button) findViewById(R.id.exit);</p><p>playBtn.setOnClickListener(this);<br />stopBtn.setOnClickListener(this);<br />pauseBtn.setOnClickListener(this);<br />exitBtn.setOnClickListener(this);</p><p>connection();<br />}</p><p>private void connection() {<br />Intent intent = new Intent("com.homer.remote.remoteMusicReceiver");<br />bindService(intent, sc, Context.BIND_AUTO_CREATE);// bindService<br />}</p><p>@Override<br />public void onClick(View v) {</p><p>try {<br />switch (v.getId()) {<br />case R.id.play:<br />musicService.play();<br />break;<br />case R.id.stop:<br />if (musicService != null) {<br />musicService.stop();<br />}<br />break;<br />case R.id.pause:<br />if (musicService != null) {<br />musicService.pause();<br />}<br />break;<br />case R.id.exit:<br />this.finish();<br />break;<br />}<br />} catch (RemoteException e) {<br />e.printStackTrace();<br />}<br />}</p><p>private ServiceConnection sc = new ServiceConnection() {<br />@Override<br />public void onServiceConnected(ComponentName name, IBinder service) {//connect Service<br />musicService = IMusicControlService.Stub.asInterface(service);<br />}</p><p>@Override<br />public void onServiceDisconnected(ComponentName name) {//disconnect Service<br />musicService = null;<br />}</p><p>};</p><p>@Override<br />public void onDestroy(){<br />super.onDestroy();</p><p>if(sc != null){<br />unbindService(sc);// unBindService<br />}<br />}<br />}
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等)

源碼下載

參考推薦:

Service (android developer)

Android Service 服務(一)—— Service

Android Service 服務(二)—— BroadcastReceiver

android中service和aidl詳細整理

Android Service AIDL

android筆記--Service與AIDL

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.