1. 程式人生 > >Service綁定模式

Service綁定模式

positon 說明 schema lag art hand layer isp xtend

Service綁定模式
使用綁定的Service能夠實現組件與Service的通信。


組件與被綁定的Service能夠不歸屬於同一個應用程序。因此通過綁定Service能夠實現進程間通信。
調用bindService(Intent service,ServiceConnectionconn,int flags)方法就可以實現當前組件與Service的綁定。
參數說明
Intent service:配置被激活的Service組件,該Intent能夠是顯式的,也能夠是隱式的;
ServiceConnection conn:當前組件與被激活的Service的連接對象,當成功的以綁定模式激活Service後,該

Service的onBlind()方法的返回值(非null)對象被回傳到當前組件,即當前組件與被激活的Service存在同樣的IBinder對象;


關於Service的onBind()方法
在綁定Service時,定義的Service類中,onBind()方法應該返回一個非null的值。
onBind()方法的返回值類型是IBinder類型。IBinder是接口。開發者能夠自定義類實現該接口
Google官方並不推薦開發者直接定義類實現IBinder接口,而是通過繼承Binder類就可以,Binder類是
IBinder接口的實現類
假設onBind()方法的返回值是null,則該綁定過程是失敗的,雖然Service也會運行onCreate()方法開始工作。
但其它的組件無法與Service通信。


實現Activity綁定Service的開發過程例如以下:
創建Activity類繼承android.app.Service類。並在AndroidMainfest.xml中註冊該Service;
在自己定義的Service類中創建IBinder的對象,作為onBind()方法的返回值;
在Activity中創建ServiceConnection的對象。
在Activity中調用bindService()方法實現與Service的綁定;
重寫Activity的onDestroy()方法,調用unbindService()方法取消與Service的綁定,以避免

當Activity被銷毀時綁定仍然存在而導致的異常。
取消綁定
當與Service綁定的組件被銷毀時,應該及時取消與Service的綁定。否則會導致異常。
在組件中。調用unbindService(ServiceConnection conn)方法則能夠取消與Service的綁定。
Service的生命周期
ServiceConnection的onServiceDisconnected()方法並不會隨著組件取消與Service的綁定而
回調,該方法僅在Service在意外情況下崩潰時被調用。
普通情況下,onRebind()方法並不會被回調,被回調的情景通常為:
與該Service的全部組件都已經取消與它的綁定,導致該Service的onUnbind()方法被回調,
且重寫了onUnbind()方法返回值為true;
該Service沒有被銷毀且再次被綁定時,則被回調onRebind()方法;

註意:以綁定模式激活的Service租價那並非粘性的,且與Service綁定的組件在退出之前必須取消綁定
,即無法保證Service依舊存在。所以。為了保證其他組件能夠銷毀,但Service依舊存在。能夠:
1、先調用startService()激活Service組件;
2、再調用bindService()實現綁定。
實現Activity與Service的通信
已知:在Service中。onBind()方法的返回值能夠被Activity獲得,即Activity與Service共同擁有一個IBinder類型的對象;
結論:開發者能夠在Service中自己定義IBinder的實現類。並在該類中定義若幹個方法,當Activity獲得該實現類
的對象時,就可以調用這些方法。
矛盾:IBinder的實現類的相關業務可能與Activity發送的Intent、service的生命周期等存在密切關系,
使用Service的內部類則無法讓Activity知曉該實現類的數據庫類型。


解決方法:使用接口定義Activity須要讓Service完畢的方法。




綁定Service時,接口的作用為:
約定一種數據類型,讓組件與Service均可使用這樣的類型的數據;
約定組件與Service通信的標準。以使得組件能夠調用相關的方法;
綁定Service的音樂播放器
在Activity中加入2個button,分別表示“播放”與“暫停”。
歌曲的播放與暫停功能由Service實現;
關於MediaPlayer暫停
通過MediaPlayer的isPlaying()方法的布爾類型返回值可知曉是否正在播放(假設沒有在播放,則不許須要暫停);
通過MediaPlayer的getCurrentPositon()方法可知曉當前的播放進度;
通過MediaPlayer的seekTo()方法可快進到指定位置在播放。

案例:

布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
     >

    <ImageButton
        android:id="@+id/pause"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/play"
        android:layout_marginLeft="58dp"
        android:onClick="pause"
        android:layout_toRightOf="@+id/play"
        android:src="@android:drawable/ic_media_pause" />

    <ImageButton
        android:id="@+id/play"
        android:onClick="play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="61dp"
        android:layout_marginTop="68dp"
        android:src="@android:drawable/ic_media_play" />

</RelativeLayout>
MainActivity,

package com.example.music_service;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

public class MainActivity extends Activity {
	private ServiceConnection conn;
	private Player player;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		conn = new InnerServiceConnection();
		int flags = BIND_AUTO_CREATE;
		Intent service = new Intent(this,PlayService.class);
		bindService(service, conn, flags);
	}
	public void pause(View view){
		player.playMusic();
	}
	public void play(View view){
		player.pauseMusic();
	}
	private class InnerServiceConnection implements ServiceConnection{

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			player = (Player) service;
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			
		}
		
	}
	protected void onDestroy(){
		unbindService(conn);
		super.onDestroy();
	}
	
}
Service:

package com.example.music_service;

import java.io.IOException;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;

public class PlayService extends Service{
    private MediaPlayer player;
    private int Current;
    @Override
    public void onCreate() {
    	// TODO Auto-generated method stub
    	player = new MediaPlayer();
    	player.setOnPreparedListener(new InnerPreparedListener());
        player.setOnCompletionListener(new InnerCompletionListener());
    }
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return new InnerBinder();
	}
	public class InnerBinder extends Binder implements Player{

		@Override
		public void playMusic() {
			// TODO Auto-generated method stub
			play();
		}

		@Override
		public void pauseMusic() {
			pause();
			// TODO Auto-generated method stub
		}
		
		
	}
	private void play(){
		
		try {
			 player.reset();
			 player.setDataSource(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Music/Groove Coverage - She.mp3");
			 player.prepareAsync();
//			 player.start();
		} catch (IllegalArgumentException e) {
			// TODO: handle exception
			e.printStackTrace();
		}catch(SecurityException e){
			e.printStackTrace();
		}
        catch(IllegalStateException  e){
			e.printStackTrace();
		}
        catch(IOException  e){
				e.printStackTrace();
			}
	}
	private void pause(){
		if(player.isPlaying()){
			Current = player.getCurrentPosition();
			player.pause();
		}
	}
	
	private class InnerPreparedListener implements MediaPlayer.OnPreparedListener{

		@Override
		public void onPrepared(MediaPlayer mp) {
			// TODO Auto-generated method stub
			mp.seekTo(Current);
			mp.start();
			Current = 0;
		}
		
	}
	private class InnerCompletionListener implements MediaPlayer.OnCompletionListener{

		@Override
		public void onCompletion(MediaPlayer mp) {
			// TODO Auto-generated method stub
			play();
		}
		
	}
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		player.release();
		player = null;
		super.onDestroy();
	}

}

接口:

package com.example.music_service;

public interface Player {
       void playMusic();
       void pauseMusic();
}
OK,對了,service不要忘了在AndroidMainfest.xml中配置一下

Service綁定模式