Android 自定义AIDL的实现与通信原理

以前使用到AIDL的时候感觉操作是蛮简单的,原理好像一点看不懂,后来才发现,原来原理这么复杂,怪不得光看代码看不懂。。。。。。

没办法,UML图画的太丑。。


一、先来讲讲Android进程之间的通信

差不多就是这样的一个图,进程间通信都得通过一个单一IBinder接口,Android框架在Client端放了一个BinderProxy,在服务端放了一个Binder,Binder实现了IBinder接口,而BinderProxy又是Binder的子类。其中Binder实现类中有4个比较重要的方法提下:

1.init():在类初始化的时候调用,本地方法,用来与底层的c/c++沟通,传递对象的地址(指针)

2.transact():java层使用的代码,主要内容是调用onTransact()

3.execTransact():c/c++使用的代码,也是调用onTransact()

4.onTransact():这个方法可以由Binder的子类来重写,在用到的时候会自动回调。


Android 自定义AIDL的实现与通信原理_第1张图片

在Android中每个进程都是在不同的dalvikvm上运行的,所以不同的进程间是无法靠java代码通信的。这就要用到底层的c代码,Linux驱动,这里只要先记住MyActivity端的ServiceConnection 类中方法的IBinder对象其实是一个BinderProxy对象(可以用service.getClass().getName()打印出来看看),在服务端也有个自定义的MyBinder对象(准确的说是Service中onBInd()方法中返回的那个对象),当调用到BinderProxy的transact方法时,通过底层的代码,最终会调用到MyBinder中的onTransact方法。

二、AIDL是干嘛的呢?

AIDL其实就是为了方便,将上面的东西给封装起来了,AP开发者不用知道有BinderProxy这个东西,也不用知道transact这个方法,只要调用这边接口的方法,那边实现类的方法就会执行了。

Android 自定义AIDL的实现与通信原理_第2张图片

还记得AIDL的Stub中有个anInterface方法,这个方法就是将IBinder对象放入到了他的Proxy中,为什么呢,因为他的Proxy不管做什么事,都要用到transact方法,而这个方法当然得有传回来的这个Ibinder对象来执行,所以结构就应该是Proxy中有个IBinder属性。

再来看看上图。IFakerAIDL用来模拟aidl文件,都是一个接口,图中的FakeBinder与FakeProxy实现了这个接口,其中FakeBinder是一个抽象类,具体的方法由用户自定义。当AP开发者调用了FakeProxy中的doSomeThing的时候,框架就自动去调用了IBinder中的transact方法(2,3),然后又会调用到onTransact方法(4),还记得之前说过,先记住框架的底层会帮助我们,最终调用到进程另外一端的onTransact方法。然后在FakeBinder类中,onTransact方法被调用,这个方法自然也去调用doSomeThind()方法(6),这个方法是个抽象方法,这样就会再去调用Service中返回的那个Ibinder对象的自定义方法。


上面的原理,加上AIDL文件的代码自动生成,就形成了AIDL。


三、贴上代码,模拟AIDL

1.清单文件:

首先,由于用到服务,在清单文件配上:

 
 
其中process属性指定这个服务是独立于这个进程的,也就是说这个APP会有2个进程。后面的参数是进程名

2.布局文件:

2个按钮,一个绑定,一个发送,一个文本输入框,接收要传递的数据。



    

3.java代码部分:

主要有5个类,在AIDL中用的是内部类我这里拆到外面来了。

MainActivity:

MyService:自定义服务(模拟远程)

IFakeAIDL:接口类(模拟AIDL文件)

FakeStub:远程的BInder子类

FakeProxy:Client代理类

MainActivity:

package com.aii.imitateaidl;

import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.ActionBarActivity;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity implements OnClickListener {
	private EditText textView_content;
	private Button button_bind, button_send;
	private BroadcastReceiver receiver;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		textView_content = (EditText) findViewById(R.id.textView_content);
		button_bind = (Button) findViewById(R.id.button_bind);
		button_send = (Button) findViewById(R.id.button_send);

		button_bind.setOnClickListener(this);
		button_send.setOnClickListener(this);

		receiver = new BroadcastReceiver() {

			@Override
			public void onReceive(Context context, Intent intent) {

				String content = intent.getStringExtra("content");
				if (content != null) {
					Toast.makeText(MainActivity.this, content,
							Toast.LENGTH_SHORT).show();
				}

			}
		};
		IntentFilter filter = new IntentFilter("com.aii.broadcast");
		registerReceiver(receiver, filter);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button_bind:
			// 绑定服务
			Intent intent = new Intent(this, MyService.class);
			bindService(intent, conn, Context.BIND_AUTO_CREATE);
			break;
		case R.id.button_send:
			// 先判断文本框内容
			String content = textView_content.getText().toString().trim();
			if (TextUtils.isEmpty(content)) {
				Toast.makeText(this, "请输入要传递的内容", Toast.LENGTH_SHORT).show();
				return;
			}
			if (binder != null) {
				try {
					// 调用接口方法
					binder.doLog(content);
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
			break;
		}

	}

	private IFakeAIDL binder;
	private ServiceConnection conn = new ServiceConnection() {

		@Override
		public void onServiceDisconnected(ComponentName name) {
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// 将service装入自定义的FakeProxy中
			binder = FakeStub.asInterface(service);
		}
	};

	@Override
	protected void onDestroy() {
		unbindService(conn);
		unregisterReceiver(receiver);
		super.onDestroy();
	}
}

MyService:
package com.aii.imitateaidl;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;

public class MyService extends Service {

	public static final int MESSAGE_LOG = 1;
	public static Handler handler;

	@Override
	public IBinder onBind(Intent intent) {
		return new MyBinder();
	}
	//打印Toast信息,远程发生广播给主线程,如果不需要Toast,可无视此部分
	@Override
	public void onCreate() {
		super.onCreate();
		new Thread(new Runnable() {

			@Override
			public void run() {
				Looper.prepare();

				handler = new Handler() {
					@Override
					public void handleMessage(Message msg) {
						switch (msg.what) {
						case MESSAGE_LOG:
							Intent intent = new Intent("com.aii.broadcast");
							intent.putExtra("content", (String) msg.obj);
							sendBroadcast(intent);
							break;

						default:
							break;
						}
					}
				};

				Looper.loop();
			}
		}).start();
	}

	class MyBinder extends FakeStub {

		@Override
		public void doLog(String content) throws RemoteException {
			Log.i("MainActivity", content);
			
			//打印Toast信息,远程发生广播给主线程,如果不需要Toast,可无视此部分
			Message msg = Message.obtain();
			msg.what = MESSAGE_LOG;
			msg.obj = content;
			handler.sendMessage(msg);
		}

	}

}
IFakeAIDL:

package com.aii.imitateaidl;

import android.os.RemoteException;

interface IFakeAIDL {
	
	int DO_LOG=0;
	void doLog(String content) throws RemoteException;
}


FakeStub:

package com.aii.imitateaidl;

import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;

abstract class FakeStub extends Binder implements IFakeAIDL {

	public static IFakeAIDL asInterface(IBinder binder) {
		//简化版。。。
		if (binder != null) {
			return new FakeProxy(binder);
		}
		return null;
	}

	@Override
	protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
			throws RemoteException {
		switch (code) {		
		case IFakeAIDL.DO_LOG:
			//code与Proxy中的对应,对应的code传递不同的信息,可执行不同的方法
			doLog(data.readString());
			return true;

		default:
			break;
		}

		return super.onTransact(code, data, reply, flags);
	}

}

FakeProxy:

package com.aii.imitateaidl;

import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;

public class FakeProxy extends Binder implements IFakeAIDL {
	private IBinder binder;

	public FakeProxy(IBinder binder) {
		this.binder = binder;
	}

	@Override
	public void doLog(String content) throws RemoteException {
		Parcel data = Parcel.obtain();
		Parcel reply = Parcel.obtain();
		data.writeString(content);
		try {
			//表面上是doLog方法,其实是封装了transact方法来实现
			binder.transact(IFakeAIDL.DO_LOG, data, reply, 0);
		} finally {
			data.recycle();
			reply.recycle();
		}
	}
	


}


代码地址: http://download.csdn.net/detail/q291611265/8607549

你可能感兴趣的:(Android 自定义AIDL的实现与通信原理)