AIDL/IPC Android AIDL/IPC 进程通信机制——超详细讲解及用法案例剖析(播放器)

首先引申下AIDL,什么是AIDL呢?IPC? ------ Designing a Remote Interface Using AIDL

通常情况下,我们在同一进程内会使用Binder、BroadCastReciver让Service跟Activity进行通信,数据交互,数据共享,但是跨进程呢?

IPC:IPC接口,IPC接口本地代理  ------  Implementing IPC Using AIDL

AIDL意为:Android Interface Define Language 即 Android 接口描述语言

与J2ee的区别:Java中不允许跨进程内存共享,只传递对象,采用RMI方式,也可以通过序列化传递对象

Android AIDL: 采用AIDL方式,可以传递Bundle,实现起来稍微麻烦些

实现过程:在服务端定义AIDL文件,ADT插件编译器将其编译之后,会在R文件同级目录文件下生成.java文件,轻量级,使用代理类在客户端和实现层间传

递值

语法:可以申明接口和方法,参数和返回值不是任何类型,不需要申明import,String,charSequence等

AIDL使用起来也不是很麻烦,我个人感觉很实用!所以今天就说说关于AIDL的特性,很多朋友在自己的博客只是说它的理论而不是写一些实例来讲解,我个人感觉你只是说说他的

理论,一般人根本就看不懂,而且本来就是很抽象的东西,又摸不着,你们写了也是白写!

完全不顾新手的感受,应该是写一些小例子,让大家参与进来一起学习和探讨效果才最佳!而且也不是一大堆的文字,看起来也不会那么乏味,大家说是不?

下面就开始今天的AIDL/IPC讲解与学习吧~,概念都讲的差不多了,接下来就是实战,代码小例子给初学者细嚼慢咽

从服务端线程开始写,结构图:


EngineerJspRemoteService.aidl 写完之后保存,就会在gen文件自动创建一个.java文件


EngineerJspService.java

package com.example.engineerjspserver;
/**
 * AIDL/IPC 
 * @author Engineer-Jsp
 * @date 2014.11.17
 * */
import java.io.FileDescriptor;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class EngineerJspService extends Service{
	private static final String TAG = "EngineerJspService";
    MediaPlayer player;
	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "EngineerJspService is onBind..."+"\n来自客户端的绑定操作已经完成...");
		if(player==null){
			player = MediaPlayer.create(this, R.raw.music);
			player = new MediaPlayer();
			try {
				FileDescriptor file = getResources().openRawResourceFd(R.raw.music).getFileDescriptor();
				player.setDataSource(file);
				player.setLooping(true);
			} catch (Exception e) {
				Log.d(TAG, e.toString());
			}
			Log.d(TAG, "player is created..."+"\n服务端播放器已经实例化,准备就绪...");
		}
		return binder;
	}
	private IBinder binder = new EngineerJspRemoteService.Stub() {
		
		@Override
		public void onStop() throws RemoteException {
			try {
				if(player.isPlaying()){
					Log.d(TAG, "客户端进程对服务端进程执行了暂停操作...");
					player.stop();
				}
			} catch (Exception e) {
				Log.d(TAG, e.toString());
			}
		}
		
		@Override
		public void onPause() throws RemoteException {
			try {
				if(player.isPlaying()){
					return;
				}
				Log.d(TAG, "客户端进程对服务端进程执行了开始操作...");
				player.prepare();
				player.start();
			} catch (Exception e) {
				Log.d(TAG, e.toString());
			}
		}
	};
	public boolean onUnbind(Intent intent) {
		if(player!=null){
			player.release();
		}
		Log.d(TAG, "EngineerJspService is onUnBind..."+"\n客户端已经解绑断线,服务停止了...");
		return super.onUnbind(intent);
		
	};

}
配置文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.engineerjspserver"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
              <activity
            android:name="com.example.engineerjspserver.MainAcivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
         <service android:name=".EngineerJspService" android:process=":remote">
            <intent-filter >
                <action android:name="com.example.engineerjspserver.EngineerJspService"/>
            </intent-filter>
         </service>
    </application>

</manifest>

当完成上述操作之后,需要在res目录下导入测试文件,比如我的测试文件一个music.mp3,需要与layout文件同级


搞定服务端之后,接下来就是客户端线程编写,之后进行进程通信测试

把服务端的aidl文件所在的包全部拷贝到客户端的src下,把aidl文件除外的全部删掉


EngineerJspActivity.java

package com.example.engineerjspclient;
/**
 * AIDL/IPC
 * @author Engineer-Jsp
 * @date 2014.11.17
 * */
import com.example.engineerjspserver.EngineerJspRemoteService;

import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
public class EngineerJspActivity extends Activity {
	private static final String TAG = "EngineerJspActivity";
	private static final String ACTION = "com.example.engineerjspserver.EngineerJspService";
	private EngineerJspRemoteService EJService;
	private boolean isBind = false;
	private Button onPause,onStart;
	
	private ServiceConnection connection = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {
			isBind = false;
			EJService = null;
			Log.d(TAG, "onServiceDisconnected" +
					"————"+"包名:"+name.getPackageName()+" "+"类名: "+name.getClassName()+"\n当客户端线程断线操作,服务将被清空...");
		}
		@Override
		public void onServiceConnected(ComponentName name, IBinder ibinder) {
			EJService = EngineerJspRemoteService.Stub.asInterface(ibinder);
			isBind = true;
			Log.d(TAG, "onServiceConnected————"+"包名:"+name.getPackageName()+" "+"类名: "+name.getClassName()+" "+"ibinder对象: "+ibinder.toString()+"\n客户端线程与服务端线程连接中...");
		}
	};
  	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_engineer_jsp);
		Log.d(TAG, "客户端线程Activity创建成功,初始化控件与绑定服务中...");
		Bind();
		intiView();
	}
  	@Override
  	protected void onDestroy() {
  		UnBind();
  		Log.d(TAG, "客户端线程被销毁,活动被解绑停止了...");
  		super.onDestroy();
  	}
  	public void Bind(){
  		Log.d(TAG, "Activity已经创建完成,执行绑定服务端线程活动中...");
  		Intent intent = new Intent(ACTION);
  		bindService(intent, connection, BIND_AUTO_CREATE);
  	}
  	public void UnBind(){
  		if(isBind){
  			Log.d(TAG, "Activity被销毁了,与服务端线程的通信将被解绑停止...");
  			unbindService(connection);
  			EJService = null;
  			isBind = false;
  		}
  	}
  	private void intiView(){
  		onPause = (Button)findViewById(R.id.onPause);
  		onStart = (Button)findViewById(R.id.onStop);
  		onPause.setOnClickListener(listener);
  		onStart.setOnClickListener(listener);
  		Log.d(TAG, "服务端线程的组件初始化完毕...");
  	}
  	private OnClickListener listener = new OnClickListener(){

		@Override
		public void onClick(View view) {
			if(view.getId()==R.id.onPause){
				try {
					EJService.onPause();
					Log.d(TAG, "客户端线程对服务端线程执行了播放操作...");
					Toast.makeText(EngineerJspActivity.this,"客户端线程对服务端线程执行了播放操作...", Toast.LENGTH_SHORT).show();
				} catch (Exception e) {
					Log.d(TAG, e.toString());
				}
			}else{
				try {
					EJService.onStop();
					Log.d(TAG, "客户端线程对服务端线程执行了暂停操作...");
					Toast.makeText(EngineerJspActivity.this,"客户端线程对服务端线程执行了暂停操作...", Toast.LENGTH_SHORT).show();
				} catch (Exception e) {
					Log.d(TAG, e.toString());
				}
			}
		}
  		
  	};
}

activity_engineer_jsp.xml

<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".EngineerJspActivity" >

    <Button
        android:id="@+id/onStop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/button1"
        android:layout_marginTop="42dp"
        android:text="onStop" />

    <Button
        android:id="@+id/onPause"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/onStop"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/onStop"
        android:text="onPause" />

</RelativeLayout>
配置文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.engineerjspclient"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.engineerjspclient.EngineerJspActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

启动服务端进程与客户端进程(不在同一个进程内,也就是不在同一个APK程序之内),在DDMS里进行进程和堆栈查看


当服务端进程开启之后,会等待客户端进程接入与操作,类似c/s模式,Socket,客户端进程开启之后,服务端测试数据如下


客户端测试数据:


服务测试:

客户端进程对服务端进程执行了播放操作:



客户端进程对服务端进程执行了暂停操作:




两个进程项目图结构:


AIDL这个小实例内容就这么多,概念也说得差不多了,你们好好看看,消化消化~

更多精彩尽在本博,欢迎大家一起学习和交流~!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Engineer-Jsp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值