Android中的IPC方式AIDL
IPC的全称是 inter-progress communication就是进程间通信,IPC不是Android独有的任何一个操作系统都需要IPC机制。当然了,我们只说Android,因为别的我也不会……。我们先说说AIDL的用处,只要就是跨进程通讯,例如我们打开的程序1想访问另外一个程序2中的某些方法或者数据时,就可能会用到AIDL,其实我们一般都用过AIDL只是你可能不知道,就像Android中的ContentProvider还有Messenger的底层其实都是AIDL实现的。
用法:
工程1:新建一个包,包里新建一个.aidl结尾的文件,.aidl文件的写法和接口类似,只是不能有修饰符,之后刷新工程,会在gen目录下系统自动生成一个包里面有个.java文件,然后把这个包连同里面的文件拷贝到工程2的gen目录下。
工程2:把接收到的数据通过stub类的asInterface方法转换成需要的类型,然后就可以使用里面的方法了。
上面的说法感觉很抽象,接下来就举个栗子吧,这个栗子实现的功能就是同时开启两个程序,程序2可以获取程序1方法中的数据:
两个工程一个叫AIDL服务,一个叫AIDL客户端
AIDL服务的工程目录如下:
MainActivity.java里都是自动生成那些,我什么都没写。
Data.aidl的代码如下,这里的两个方法都是随便起的:
package com.zhangdi.aidl;
interface Data {
String getName ();
void setNumber(String num);
}
Myservice.java的代码如下:
package com.example.aidlservice;
import com.zhangdi.aidl.Data;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return new Mybinder();
}
private class Mybinder extends Data.Stub {//继承AIDL中的stub类
@Override
public String getName() throws RemoteException {//实现.aidl文件中定义的方法
// TODO Auto-generated method stub
return "zhangsan";
}
@Override
public void setNumber(String num) throws RemoteException {
Log.i("zhangsan", "num = " + num);
}
}
}
Manifest文件配置如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.aidlservice"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
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="com.example.aidlservice.MyService">
<intent-filter>
<action android:name="com.zhangdi.startService"/>
</intent-filter>
</service>
</application>
</manifest>
AIDL客户端的工程目录如下:
com.zhangdi.aidl这个包是从AIDL服务里考过来的。
MainActivity.java里的代码如下:
package com.example.aidlclient;
import com.zhangdi.aidl.Data;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends Activity {
private ServiceConnection conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startService(View v) {
Intent intent = new Intent("com.zhangdi.startService");//启动服务的隐式意图
conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try{
Data data = Data.Stub.asInterface(service);
Log.i("zhangdi", data.getName());//获取AIDL服务里getName方法中的数据
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
bindService(intent, conn, BIND_AUTO_CREATE);
}
}
这个栗子很简单,接下来我们来分析一下系统自动生成的在gen目录下的com.zhangdi.aidl中的Data.java类。
我为了好看修改了一下文件的顺序,蓝色Data是最外面的接口,紫色是Data的内部类,黄色是紫色的内部类。Data类集成了IInterface接口,同时他自己也还是一个接口,所有可以在Binder中传输的接口都需要继承IInterface接口。首先Data类声明了两个方法,很显然这都是我们在Data.aidl中声明的方法,这也是为了后续实现Data接口类能够实现我们需要的方法,然后他在内部抽象类Stub中声明了两个常量用来区分两个方法,Stub同样没有实现我们需要的两个方法,显然这个两个方法需要由Stub的继承类来实现,asInterface方法判断了传递进来的IBinder对象是是在同一个进程中还是不同进程,相同进程则返回Stub类本身对象,不调用transact方法保存可以跨进程传递的信息,只有在不同进程返回的是Stub.Proxy对象,才调用transact方法,调用transact方法的逻辑由Stub的内部类Proxy来完成。
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\workspace6\\AIDL服务\\src\\com\\zhangdi\\aidl\\Data.aidl
*/
package com.zhangdi.aidl;
public interface Data extends android.os.IInterface
{
public java.lang.String getName() throws android.os.RemoteException;
public void setNumber(java.lang.String num) throws android.os.RemoteException;
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.zhangdi.aidl.Data
{
//Binder的唯一标示
private static final java.lang.String DESCRIPTOR = "com.zhangdi.aidl.Data";
static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_setNumber = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.zhangdi.aidl.Data interface,
* generating a proxy if needed.
*/
//asInterface方法是把相同进程中的IBinder对象强转为Data类型接口对象的方法,如果在不同进程则产生一个proxy类型的对象
public static com.zhangdi.aidl.Data asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.zhangdi.aidl.Data))) {
return ((com.zhangdi.aidl.Data)iin);
}
return new com.zhangdi.aidl.Data.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
//这个方法是运行在服务端的Binder线程池中,当客户端发起跨进程访问请求时,远程请求会通过系统底层封装后交由这个方法来处理。这个方法的原型是protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags),服务端通过code可以确定客户端请求的目标是哪个方法,接着从data中取出方法所需参数,然后执行目标方法,最后通过reply写入返回值,最后需要注意的是如果最后方法返回的boolean值是false,则客户端请求失败,因此我们可以通过这个特性做权限校验,毕竟我们不希望任何进程都可以远程调用我们的进程。
@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_getName:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getName();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_setNumber:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
this.setNumber(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.zhangdi.aidl.Data
{
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;
}
//这个方法是运行在客户端的,实现过程:首先创建该方法需要的Parcel类型的输入对象_data和输出对象_reply以及返回值对象_result,如果该方法有参数则把参数写入_data中,接着调用transact方法来发起远程过程调用请求,同时当前线程挂起,在transact方法中会调用服务器端的OnTransact方法,直至远程过程调用返回结果,当前线程才继续执行,从_reply中取出结果,最后返回_reply中的数据。
@Override public java.lang.String getName() 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);
mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
//这个方法与上边的方法实现原理基本一样。
@Override public void setNumber(java.lang.String num) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(num);
mRemote.transact(Stub.TRANSACTION_setNumber, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
}
}
最后注意,有时候我们跨进程需要传递的参数或者返回值是自定义类型时,我们需要把实体类定义到aidl包下,并且在aidl包里再声明一个实体类对应的.aidl文件,如下:
package com.zhangdi.aidl;
parcelable MyUser;
然后在data.aidl里用到这个类的对象时需要
import com.zhangdi.aidl.MyUser;
如果使用这个类的对象作为参数时,需要指明参数是in还是out型
void setUser(in MyUser user);
我写了一下小demo上传到了github上 demo地址
Android中的IPC方式AIDL相关推荐
- Android中的IPC方式
Android中的IPC方式 在上一篇,我们探索了IPC的基本知识,序列化,和Binder的基本实现原理 本篇我们来看看Android中的一些具体的跨进程通信的方式 使用Bundle 我们知道,四大组 ...
- Android中进程间通信(IPC)方式总结
IPC为进程间通信或跨进程通信,是指两个进程进行进程间通信的过程.在PC和移动设备上一个进程指的是一个程序或者一个应用,所以我们可以将进程间通信简单理解为不同应用之间的通信,当然这种说法并不严谨. 在 ...
- Android中的IPC机制
Android IPC简介 IPC是Inter-Process Communication的缩写,含义就是进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程.那么什么是进程,什么是线程,进程 ...
- Android中进程间通讯 AIDL
Android中进程间通讯 AIDL IDL Interface Description Language 接口描述语言 AIDL Android IDL 适用场景: client进程必须是A ...
- Android开发之IPC进程间通信-AIDL介绍及实例解析
一.IPC进程间通信 IPC是进程间通信方法的统称,Linux IPC包括以下方法,Android的进程间通信主要采用是哪些方法呢? 1. 管道(Pipe)及有名管道(named pipe):管道可用 ...
- Android中使用SAX方式解析XML文件
转载http://blog.csdn.net/cjjky/article/details/6666834 在Android中解析XML文主要有三种方式,分别为Simple API for XML(SA ...
- android 中xml解析方式
2019独角兽企业重金招聘Python工程师标准>>> XML在各种开发中都广泛应用,Android也不例外.作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重 ...
- 关于Android中XML解析方式
XML解析一般有三种方式:DOM .SAX.PULL. SAX解析器:它是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作.当事件源产生事件后,调用事件处理器相应的 ...
- android 通话结束广播,在Android中以编程方式结束通话
侃侃尔雅 您无需成为系统应用程序.首先,com.android.internal.telephony在您的项目中创建包,并将其放入名为" ITelephony.aidl" 的文件中 ...
- 如何在android中设置背景,如何在Android中以编程方式设置背景可绘制
MMTTMM layout.setBackgroundResource(R.drawable.ready);是正确的.实现它的另一种方法是使用以下方法:final int sdk = android. ...
最新文章
- windows下用GCC编译DLL
- 如何判断数组所有数都不等于一个数_【每日算法Day 91】求解数组中出现次数超过1/3的那个数
- centos安装zendopcache
- STL Vector使用例程
- ningbooj--1655--木块拼接(贪心)
- vivado烧写FPGA速度调节
- scrollview复用节点_利用ScrollView实现TableView效果(实现复用)
- Chapter 7:Statistical-Model-Based Methods
- 验证测试线时为什么会出现“正损耗”?
- 安利几个优质NLP开源项目!搜索、问答、情感分析…
- 正则表达式搜魂者(转:清清月儿 )
- Spring Boot Shiro权限管理--自定义 FormAuthenticationFilter验证码整合
- Mac删除Windows10后空间丢失解决
- 小论坛 之Linux服务器搭建Apache PHP mysql 环境
- 开源跨平台计算机视觉库OpenCV 4.0正式发布
- php计算工资的代码,php计算税后工资的方法_PHP
- 烤仔看世界 | “女王”的骗局
- JSON、AJAX、Maven
- 分布式事务之——两段式、三段式
- 12V转5V2A电源模块的电路集合
热门文章
- 3dmax材质通道插件_3dmax插件外挂神器【疯狂模渲大师蓝色经典版】第九章:渲染后期教程...
- ajax更换内容执行函数,在ajax成功调用另一个ajax函数
- php form表单提交代码,PHP之表单的提交
- Django:报错 unsupported format character ‘Y‘ (0x59) at index 70
- MySQL查询日期类数据常用函数
- ElementUI:设置table的背景透明、根据表格情况设置背景色、设置文字颜色、文字左右间距、表头、每一行高度
- TimeSpan asp.net中时间的运算
- 深度学习笔记_基本概念_逆卷积的详细解释ConvTranspose2d(fractionally-strided convolutions)
- 随手记_研究生怎样做学术
- 图像语义分割(4)-SegNet:深度全卷积编解码结构