进程与进程间的通信(一)——Aidl

提起进程间的通信我们就会想到Aidl,今天就个人理解的Aidl进行阐述,如有不当之处还望大家多多指教。好了,不说废话了,下面我们就进入今天的正题——Aidl,进程间的通信大使。

AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。是的,首先我们知道的第一点就是:AIDL是一种语言。既然是一种语言,那么相应的就很自然的衍生出了一些问题:

为什么要设计出这么一门语言?

它有哪些语法?

我们应该如何使用它?

下面我们就这些问题进行分开描述:

为什么要设计出这么一门语言?

设计这门语言的目的是为了实现进程间通信。
每一个进程都有自己的Dalvik VM实例,都有自己的一块独立的内存,都在自己的内存上存储自己的数据,执行着自己的操作,都在自己的那片狭小的空间里过完自己的一生。每个进程之间都你不知我,我不知你,就像是隔江相望的两座小岛一样,都在同一个世界里,但又各自有着自己的世界。而AIDL,就是两座小岛之间沟通的桥梁。相对于它们而言,我们就好像造物主一样,我们可以通过AIDL来制定一些规则,规定它们能进行哪些交流——比如,它们可以在我们制定的规则下传输一些特定规格的数据。
总之,通过这门语言,我们可以愉快的在一个进程访问另一个进程的数据,甚至调用它的一些方法

它有哪些语法

其实AIDL这门语言非常的简单,基本上它的语法和 Java 是一样的,只是在一些细微处有些许差别——毕竟它只是被创造出来简化Android程序员工作的,太复杂不好——所以在这里我就着重的说一下它和 Java 不一样的地方。主要有下面这些点:
文件类型:用AIDL书写的文件的后缀是 .aidl,而不是 .java。
数据类型: Java基本类型,String,List,Map,CharSequence

我们如何使用它?

IBinder是远程对象的基本接口,是为了高性能而设计的轻量级远程调用机制的核心部分。但他 不仅用于远程调用,也用于进程内调用。该接口定义了与远程对象间交互的协议。但不要直接实现 这个接口,而是继承(extends)Binder。

IBinder是Android给我们提供的一个进程间通信的一个接口,而我们一般是不直接实现这个接口的, 而是通过继承Binder类来实现进程间通信!是Android中实现IPC(进程间通信)的一种方式!

Binder机制给我们带来的最直接的好处就是: 我们无需关心底层如何实现,只需按照AIDL的规则,自定义一个接口文件, 然后调用调用接口中的方法,就可以完成两个进程间的通信了!


到这里相信大家已经对Aidl有了一定的了解,那么此时,问题又来了。什么是IPC啊?它又是个什么鬼?别急别急,容我歇息一番后做出解答。

IPC这个名词,他的全名叫做:跨进程通信(interprocess communication), 因为在Android系统中,个个应用程序都运行在自己的进程中,进程之间一般是无法直接进行数据交换的, 而为了实现跨进程,Android给我们提供了上面说的Binder机制,而这个机制使用的接口语言就是: AIDL(Android Interface Definition Language)

这种接口语言并非真正的编程 语言,只是定义两个进程间的通信接口而已!而生成符合通信协议的Java代码则是由Android SDK的 platform-tools目录下的aidl.exe工具生成,生成对应的接口文件在:gen目录下,一般是:Xxx.java的接口! 而在该接口中包含一个Stub的内部类,该类中实现了在该类中实现了IBinder接口与自定义的通信接口, 这个类将会作为远程Service的回调类——实现了IBinder接口,所以可作为Service的onBind( )方法的返回值!

在开始编写AIDL接口文件前,我们需要了解下编写AIDL的一些注意事项:
AIDL注意事项:
接口名称需要与aidl文件名相同
接口和方法前面不要加访问权限修饰符:public ,private,protected等,也不能用static final!
AIDL默认支持的类型包括Java基本类型,String,List,Map,CharSequence,除此之外的其他类型都 需要import声明,对于使用自定义类型作为参数或者返回值,自定义类型需要实现Parcelable接口


说了这么多,接下来当然就是贴代码了,但是,再贴代码之前,还是先给出步骤:

服务端步骤如下:

Step 1:创建AIDL文件:
Step 2:自定义我们的Service类,完成下述操作:
1)继承Service类,同时也自定义了一个类用来继承MyServiceAIDL.Stub类 就是实现了MyServiceAIDL接口和IBinder接口
2)实例化自定义的Stub类,并重写Service的onBind方法,返回一个binder对象!
Step 3:在AndroidManifest.xml文件中注册Service

客户端步骤如下:

直接把服务端的那个aidl文件复制过来(包名要一致)

1)创建 ServiceConnection接口 实例

2) 调用bindService绑定远程Service bindService(service,conn,BIND_AUTO_CREATE); 

3)和本地Service不同,绑定远程Service的ServiceConnection并不能直接获取Service的onBind( )方法 返回的IBinder对象,只能返回onBind( )方法所返回的代理对象,需要做如下处理: binder= MyServiceAIDL.Stub.asInterface(service); 再接着完成初始化,以及按钮事件等就可以了


下面给出代码:

首先是aidl文件:它的后缀名一定要是.aidl

package us.mifeng;
interface Authority{
	String getName(int num);
}
服务端service:

public class MyService extends Service{
	String name[]={"11","22","33","44","55"};

	@Override
	public void onCreate() {
		super.onCreate();
	}
	@Override
	public IBinder onBind(Intent intent) {
		return new MyBinder();
	}
	class MyBinder extends Stub{

		@Override
		public String getName(int num) throws RemoteException {
			int i = num%5;
			return name[i];
		}
		
	}
}
清单文件中的代码如下:

 <service android:name="cn.lzl.aidldemoa.MyService">
            <intent-filter >
                <action android:name="cn.bgs.aidldemo"/>
                
            </intent-filter>
        </service>
然后就是客户端的代码了。在这之前一定要先把服务端的aidl文件copy过来。一定一定。。。


public class MainActivity extends Activity {

	private Button mBtn;
	private EditText mEd;
	private TextView mTv;
	private Authority binder;
	private ServiceConnection conn=new ServiceConnection() {
		

		@Override
		public void onServiceDisconnected(ComponentName name) {
			
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			Log.e("", "===================");
			binder = Authority.Stub.asInterface(service);
			
		}
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mBtn=(Button) findViewById(R.id.mBtn);
		mEd=(EditText) findViewById(R.id.mEd);
		mTv=(TextView) findViewById(R.id.mTv);
		Intent intent =new Intent();
		intent.setAction("cn.bgs.aidldemo");
		bindService(intent, conn, Service.BIND_AUTO_CREATE);
		mBtn.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
               
					int result=Integer.valueOf(mEd.getText().toString());
					try {
						String data=binder.getName(result);
						Log.e("", "================="+data);
						mTv.setText(data);
					} catch (RemoteException e) {
						e.printStackTrace();
				}
				
				
			}
				
		});
	}
}

忘记说一件事情,前几天在给学生讲这个代码的时候,遇到了一个小小的bug,那就是空指针异常,在我查阅资料后发现是因为 在android 5.0之后不能采用隐式跳转,需要在intent.setAction();方法之后,加一行代码。 即intent.setPackage("服务端MyService的包名");

然后,方便以后有遇到这个问题的新手查阅,特写此博客。(允许我小小的装一下逼(●'◡'●))。


猜你喜欢

转载自blog.csdn.net/lzllzllhl/article/details/72834848
今日推荐