Android 自定义AIDL的实现与通信原理
来源:互联网 发布:fgo花嫁尼禄宝具本数据 编辑:程序博客网 时间:2024/06/05 09:38
以前使用到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中每个进程都是在不同的dalvikvm上运行的,所以不同的进程间是无法靠java代码通信的。这就要用到底层的c代码,Linux驱动,这里只要先记住MyActivity端的ServiceConnection 类中方法的IBinder对象其实是一个BinderProxy对象(可以用service.getClass().getName()打印出来看看),在服务端也有个自定义的MyBinder对象(准确的说是Service中onBInd()方法中返回的那个对象),当调用到BinderProxy的transact方法时,通过底层的代码,最终会调用到MyBinder中的onTransact方法。
二、AIDL是干嘛的呢?
AIDL其实就是为了方便,将上面的东西给封装起来了,AP开发者不用知道有BinderProxy这个东西,也不用知道transact这个方法,只要调用这边接口的方法,那边实现类的方法就会执行了。
还记得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.清单文件:
首先,由于用到服务,在清单文件配上:
<service android:name="com.aii.imitateaidl.MyService" android:process=":remote" > </service>其中process属性指定这个服务是独立于这个进程的,也就是说这个APP会有2个进程。后面的参数是进程名
2.布局文件:
2个按钮,一个绑定,一个发送,一个文本输入框,接收要传递的数据。
<LinearLayout 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:orientation="vertical" > <Button android:id="@+id/button_bind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="bindService" /> <EditText android:id="@+id/textView_content" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="请输入要传递的信息" /> <Button android:id="@+id/button_send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="sendMessage" /></LinearLayout>
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;@Overrideprotected 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() {@Overridepublic 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);}@Overridepublic 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() {@Overridepublic void onServiceDisconnected(ComponentName name) {}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 将service装入自定义的FakeProxy中binder = FakeStub.asInterface(service);}};@Overrideprotected 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;@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}//打印Toast信息,远程发生广播给主线程,如果不需要Toast,可无视此部分@Overridepublic void onCreate() {super.onCreate();new Thread(new Runnable() {@Overridepublic void run() {Looper.prepare();handler = new Handler() {@Overridepublic 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 {@Overridepublic 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;}@Overrideprotected 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;}@Overridepublic 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();}}}
- Android 自定义AIDL的实现与通信原理
- android AIDL实现进程间的通信
- AIDL实现Android的进程通信
- AIDL实现Android进程间的通信
- Android 使用aidl实现进程间通信-传递自定义的类
- 带你一起剖析Android AIDL跨进程通信的实现原理
- 系统的进程通信(aidl)的实现原理
- AIDL的实现原理
- android中非aidl实现进程间通信(编写顺序的parcel写入与读出)
- android 进程通信之aidl 自定义数据类型
- Android实现进程间通信aidl的使用
- android使用aidl实现进程间通信的实例
- Android基础--使用AIDL实现进程间的通信
- android 用aidl实现进程间的通信
- Android AIDL使用详解 实现进程间的通信
- Android-->IPC(跨进程)通信Aidl的实现方法
- 使用AIDL实现Android的跨进程通信
- Android 使用AIDL实现进程之间的通信(一)
- 有关【年、月、日】的函数
- python写爬虫
- jpa的复合主键中关系中如何配置才能做到级联删除,我现在的问题是现在有一个学生类一个课程类,下面补充
- 奇异值分解--线性变换几何意义
- Service
- Android 自定义AIDL的实现与通信原理
- POJ,ZOJ题目分类(多篇整合版,分类很细致,全面)
- android字间距实现,textview字间距实现
- android自动调节屏幕亮度自动调节流程解析
- 阿里云CentOS搭建Git环境
- android下载和工具
- MVC4验证 用户登录特性 实现方法
- StringUtils
- java代码优化编程