Android IPC机制
来源:互联网 发布:诺基亚n900运行windows 编辑:程序博客网 时间:2024/06/05 15:59
前言:笔者之前也看了很多关于IPC之类的文章和书籍,发现这个东西真的很难理解清楚,很少有人把它介绍清楚,因为关于IPC真的特别复杂,其实我们应该都明白在Android里面,要想研究一些底层的实现,那么我们不可避免的去看源码。鉴于IPC,要想真正理解透彻你只有从源码角度看起,但是你会发现关于IPC这块底层几乎全部都是C/C++代码,看起来真的很头疼。介于技术笔者这块也只能说上层原理和作用。
IPC是Inter-Process Communication的缩写,是进程间通信意思。在说这个话题之前,我们知道在PC端我们经常也会听到关于IPC机制,Android系统是基于Linux内核的,在Linux上面它是怎么进行进程间通信的呢?在大学里面如果是学过关于操作系统,应该会了解点,进程之间通信的方式有:信号量(Signal),消息队列,消息邮箱,还有传统的管道(Pipe),或者通过文件共享的方式等等,比如说A进程将数据写入文件,B进程再去读取这个文件。其实读者应该明白,关于两个进程之间是不能够直接通信的,这个是肯定的,很简单,这是两个彼此独立的应用程序,拥有不同的内存地址,那么他们的通信其实都是通过操作系统的支持,A进程向操作系统申请一块内存空间,把该共享的数据放入,B进程也向操作系统申请读取这边内存空间,这时候就可以进行数据交换了。
那么在Android中关于进程间通信是否也像上面说的Linux一样的?
答案是否了,Android并没有继承关于Linux IPC之间的秉性,而是采用了一套自己都有的方式——Binder机制
什么是Binder?又该如何了解Binder呢?
Binder是Android之中进行进程间通信最有特色的一种,根据在工作中的性质可能会大量用到,直接来说Binder是Android系统里面提供的一个类,实现了IBinder接口。从IPC角度来说呢Binder是Android中一种跨进程通信方式,从Android Frameword角度来说,Binder是ServiceManager连接各种Manager(ActivityManager,WindowManager等等)和相应ManagerService的桥梁。从Android应用层角度来说是客户端和服务端通信的媒介。可想而知其重要性了,到这里我相信很多人都用过,在bindService的时候服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象我们就可以获取我们想要的数据。
我们知道在Android中进行进程中的通信只有一种方式,那就是在AndroidMenifest文件中给四大组件(Activity,Service,Receiver,ContentProvider)指定android:process属性,这是在一个应用之间,让不同的组件独立于一不同的进程。也就实现了多进程通信了,比如说我可以在我的Activity配置文件中加入android:process=romove属性这样就让我的这个Activity运行在一个独立的进程里面了,此时让他和service通信也就实现了IPC。这和在不同的应用之间进行进程间通信是一样的,这点需要读者注意,理解清楚。读者在网上可以看到很多通过配置android:process属性在一个应用中来实现IPC其实和我刚刚说的不同应用都是一样的。 为了让读者看起来更清楚点,我们采用在不同的应用来进行进程间通信。
Android中IPC方式主要有哪些?
1.Bundle,Intent
2.文件共享
3.AIDL
4.Messenger
5.ContentProvider
6.Socket
接下来会一一讲解,本文主要是讲解关于Android中的IPC(重点:Binder机制),关于一些服务的基本概念将不再叙述,可以参考网上的其他文章。在Android开发中Binder主要是用于服务中,接下来我们先来看一个案例,通过案例来分析。先从大家熟悉的AIDL(Android Interface Definition Language)说起。
新建项目MyProject,里面包含主Activity MainActivity.java,MyService.java,ImiddlePerson.aidl.
MainActivity.java如下:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); }}
MyService.java如下:
public class MyService extends Service { @Override public IBinder onBind(Intent arg0) { return new MyBind(); } private class MyBind extends ImiddlePerson.Stub{ @Override public String revers(String str) throws RemoteException { return str.toUpperCase(); } @Override public void print() throws RemoteException { System.out.println("print..."); } @Override public int sun(int a, int b) throws RemoteException { return a+b; } }}
ImiddlePerson.aidl.如下:
package com.xyy.demo; interface ImiddlePerson { String revers(String str); void print(); int sun(int a,int b); }
从上面代码可以看出来,代码异常简单,我们建立了ImiddlePerson.aidl.文件,在文件之中我们声明了三个简单的方法,revers方法用于客户端调用传替参数并将其转成大写。print方法无参只是打印了一句字符串,sum方法用户客户端传替两个参数过来将其相加。关于AIDL文件你需要注意,里面没有修饰符一说,所以不能写修饰符,不然就会报错,还有虽然在同一个包下,但是还是需要导包,这就是AIDL文件的特殊之处,读者需注意。
接下来你会在gen目录下看到生成的ImiddlePerson .java文件,代码如下:
/* * This file is auto-generated. DO NOT MODIFY. * Original file: C:\\TouchTest\\BadgeViewTest\\src\\com\\xyy\\demo\\ImiddlePerson.aidl */package com.xyy.demo;public interface ImiddlePerson extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.xyy.demo.ImiddlePerson { private static final java.lang.String DESCRIPTOR = "com.xyy.demo.ImiddlePerson"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.xyy.demo.ImiddlePerson interface, * generating a proxy if needed. */ public static com.xyy.demo.ImiddlePerson asInterface( android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.xyy.demo.ImiddlePerson))) { return ((com.xyy.demo.ImiddlePerson) iin); } return new com.xyy.demo.ImiddlePerson.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_revers: { data.enforceInterface(DESCRIPTOR); java.lang.String _arg0; _arg0 = data.readString(); java.lang.String _result = this.revers(_arg0); reply.writeNoException(); reply.writeString(_result); return true; } case TRANSACTION_print: { data.enforceInterface(DESCRIPTOR); this.print(); reply.writeNoException(); return true; } case TRANSACTION_sun: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.sun(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.xyy.demo.ImiddlePerson { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public java.lang.String revers(java.lang.String str) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(str); mRemote.transact(Stub.TRANSACTION_revers, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void print() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_print, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public int sun(int a, int b) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(a); _data.writeInt(b); mRemote.transact(Stub.TRANSACTION_sun, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_revers = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_print = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_sun = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); } public java.lang.String revers(java.lang.String str) throws android.os.RemoteException; public void print() throws android.os.RemoteException; public int sun(int a, int b) throws android.os.RemoteException;}
可以看到系统为我们自动生成的代码。这就是AIDL文件。
我们发现我们的ImiddlePerson是继承于IInterface接口,接着可以看到
public static abstract class Stub extends android.os.Binder implements com.xyy.demo.ImiddlePerson
到这里我们应该明白了。上面MyService.java里面的代码了。(不再叙述)。
接着我们在Manifest文件之中配置我们的MyService并配置上我们的action
<service android:name="com.xyy.demo.MyService"> <intent-filter> <action android:name="com.xyy.demo.MyService"/> </intent-filter> </service>
将其部署到我们的手机,此时一个简单的远程服务以及部署到我们的手机上了。
接下来新建项目MyProject2客户端应用,这个就比较简单了,首先你需要将之前的AIDL文件copy过来,记住连同包名一起,而且一点不能出错,否则定会反序列化失败。接着在我们的主Activity里面完成如下代码:
/** * * @author xyy * */public class MainActivity extends Activity { private ImiddlePerson iMiddPerson; public static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); } /** * 绑定方式开启服务 * @param view */ public void bind(View view){ Intent intnet = new Intent(); intnet.setAction("com.xyy.demo.MyService"); bindService(intnet, new MyConn(), BIND_AUTO_CREATE); } private class MyConn implements ServiceConnection{ @Override public void onServiceConnected(ComponentName name, IBinder service) { iMiddPerson = ImiddlePerson.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } } /** * 调用服务里面的方法 */ public void call(View view){ try { Log.d(TAG, iMiddPerson.revers("android")); Log.d(TAG, iMiddPerson.sun(20, 30)+""); iMiddPerson.print(); } catch (RemoteException e) { e.printStackTrace(); } }}
可以看到我们以绑定的方式启动服务,在绑定成功后会拿到右Binder通过转换后的AIDL对象iMiddlePerson,最后调用方法。
打印结果如下:
09-17 04:35:38.450: D/MainActivity(20584): ANDROID09-17 04:35:38.450: D/MainActivity(20584): 5009-17 04:35:38.450: I/System.out(20075): print...
这样我们的一个通过AIDL的方式的远程服务也就结束了,(如果不懂没关系,下面可以叙述。)可以发现代码特别简单,实现起来也很快,几乎不需要太多逻辑。。。。其实不然,IPC哪有这样简单,这只不过我写的特别简单的一个案例,接下来我们就开始分析。
- Android IPC机制详解
- Android IPC机制详解
- Android IPC 机制详解
- Android IPC机制 详解
- Android IPC机制详解
- Android IPC机制详解
- Android的IPC机制
- Android IPC机制详解
- Android IPC机制详解
- android IPC机制
- Android Binder IPC机制
- android ipc机制
- Android读书笔记-------IPC机制
- android 学习 IPC机制
- Android AIDL IPC机制
- android的IPC机制
- Android IPC机制
- Android的IPC机制
- C#--记录用户程序退出时间日志
- Java基础之集合框架--Collections.reverse()方法
- java.lang.ClassNotFoundException: sun.jdbc.odbc.JdbcOdbcDriver解决方案
- Android移动开发-属性动画的实现
- activeMQ发布订阅模式中中常用工具类
- Android IPC机制
- C#--生成流水号---当前时间加随机数
- 如何从零开始建立一个新的项目
- Hadoop2 伪分布式安装
- SSH与SSM学习之hibernate10——Hibernate的一级缓存
- 51单片机的中断系统(四)
- 晶振的抉择:12M和11.0592M的选择
- linux内存管理之页描述符
- C#--使用美化方法设计通用登录窗体