使用AIDL实现跨进程Service的绑定

基于在绑定Service时,与Service实现绑定的组件可以归属于不同的应用程序,因此可以实现跨进程的绑定,进而实现通信功能。在跨进程的绑定中,需要使用AIDL来定义接口,本博客将详细的介绍这种跨进程绑定、通信的方式,由于使用AIDL定义接口时,默认可用的数据类型非常有限。本博客还会介绍如何在AIDL中使用自定义的数据类型,及Parcelable接口的使用方式。

AIDL

AIDL表示"安卓接口定义语言",使用AIDL定义的接口会被开发工具生成为可实现远程访问的接口。进程间通信是组件间通信应用的“高级方式”,与组件间通信的区别在于:接口需要使用AIDL定义。由于存在两个应用程序进行通信,一般提供服务的应用程序被称为“服务端”,而调用它接口方法的应用程序称为“客户端”。

进程间的通信方式

使用AIDL实现跨进程Service的绑定_第1张图片

AIDL的创建

AIDL接口的创建方式与普通java接口的创建方式一致,区别在于:
  • AIDL文件的扩展名为.aidl,而普通java接口为.java.(我们只需要像创建普通接口那样先创建,然后把扩展名改为.aidl即可)
  • aidl不允许用任何访问权限修饰符去修饰该接口,它默认被修饰为public的。
用法示例
interface IPlayerAIDL {
	void play();
	void pause();
	void previous();
	void next();
}

在创建了AIDL接口后,开发工具会自动在gen下创建匹配的java文件。

使用AIDL远程绑定Service

在开发工具生成了匹配AIDL接口的java文件中定义了一个内部类Stub。继承了android.os.Binder并实现了该AIDL接口,所以我们在创建service中IBinder的实现类时继承该类即可。在该类中存在asInterface(IBinder obj)方法,用于将IBinder对象转换为AIDL接口实现类对象。因此在绑定Service的组件中可以该方法得到AIDL接口实现类的对象。

服务端的开发步骤:

  1. 开发AIDL接口的源文件,并保证扩展名为.aidl。
  2. 在Service中开发AIDL接口的实现类并实现接口内定义的抽象方法。
  3. 实现Service的onBind()方法,并将AIDL接口类的实现对象作为该方法的返回值。
  4. 注册Service类,并配置intent-filter(确保该Service可以被隐式激活)
  5. 部署服务端应用程序到设备上

客户端的开发步骤:

  1. 将服务端的AIDL相关文件复制到客户端中(相关包名类名不可更改)
  2. 开发ServiceConnection接口的实现类
  3. 使用隐式意图绑定服务端的Service
  4. 在ServiceConnection实现类的onServiceConnected方法中,通过Stub的asInterface方法将IBinder对象转换为AIDL接口实现类对象

接下来用一个例子来演示下它的用法,这个例子实现如下功能:
在服务端播放音乐,具有播放,暂停,上一曲,下一曲等功能,在客户端对应有相关按钮。

服务端代码如下:
PlayerService.java
public class PlayerService extends Service {
	private MediaPlayer player;//定义播放器
	private int currentPosition;//当前的播放位置
	private int musicPosition=0;
	String[] musics=new String[]{//歌曲的存放路径
			Environment.getExternalStorageDirectory().getAbsolutePath()+"/Music/d.mp3",
			Environment.getExternalStorageDirectory().getAbsolutePath()+"/Music/b.mp3",
			Environment.getExternalStorageDirectory().getAbsolutePath()+"/Music/c.mp3",
			Environment.getExternalStorageDirectory().getAbsolutePath()+"/Music/a.mp3",
	};
	@Override
	public void onCreate() {
		player=new MediaPlayer();
		//监听一首歌是否播放完成
		player.setOnCompletionListener(new OnCompletionListener() {
			
			@Override
			public void onCompletion(MediaPlayer mp) {
				//完成后播放下一首
				doNext();
			}
		});
		super.onCreate();
	}
	private void doPlay(){
		player.reset();
		try {
			player.setDataSource(musics[musicPosition]);
			player.prepare();
			//播放前先到上次播放位置
			player.seekTo(currentPosition);
			player.start();
			currentPosition=0;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	private void doPause(){
			if(player.isPlaying()){
				currentPosition=player.getCurrentPosition();
				player.pause();
			}
		}
	private void doPrevious(){
		musicPosition--;
		if(musicPosition<0){
			//第一首上一首为最后一首
			musicPosition=musics.length-1;
		}
		currentPosition=0;
		doPlay();
	}
	private void doNext(){
		musicPosition++;
		if(musicPosition>=musics.length){
			//最后一首下一首为第一首
			musicPosition=0;
		}
		currentPosition=0;
		doPlay();
	}

	@Override
	public IBinder onBind(Intent intent) {
		return new InnerBinder();
	}
	
	private class InnerBinder extends IPlayerAIDL.Stub{

		@Override
		public void play() throws RemoteException {
			doPlay();
		}

		@Override
		public void pause() throws RemoteException {
			doPause();
		}

		@Override
		public void previous() throws RemoteException {
			doPrevious();
		}

		@Override
		public void next() throws RemoteException {
			doNext();
		}
		
	}
	@Override
	public void onDestroy() {
		player.release();
		player=null;
		super.onDestroy();
	}

}

IPlayerAIDL.aidl
interface IPlayerAIDL {
	void play();
	void pause();
	void previous();
	void next();
}
AndroidManifest.xml中添加如下代码:

            
                

                
                
            
            
 
          
           

客户端代码如下:
activity_main.xml


    

    

    

    

MainActivity.java
public class MainActivity extends Activity {
	private ServiceConnection conn;
	private IPlayerAIDL player;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Intent intent=new Intent("android.intent.action.PLAYMUSIC_SERVICE");
		conn=new InnerServiceConnection();
		bindService(intent, conn, BIND_AUTO_CREATE);
	}
	private class InnerServiceConnection implements ServiceConnection{

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			player=IPlayerAIDL.Stub.asInterface(service);
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
		}
		
	}
	public void play(View v){
	    	try {
				player.play();
			} catch (RemoteException e) {
				e.printStackTrace();
			}
	    }
	public void pause(View v){
		try {
			player.pause();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}
	public void next(View v){
		try {
			player.next();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}
	public void previous(View v){
    	try {
			player.previous();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
    }
	@Override
	protected void onDestroy() {
		unbindService(conn);
		super.onDestroy();
	}
}


关于AIDL使用自定义数据类型传输可以参考这里-------------- AIDL自定义数据类型





你可能感兴趣的:(Android)