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相关推荐

  1. Android中的IPC方式

    Android中的IPC方式 在上一篇,我们探索了IPC的基本知识,序列化,和Binder的基本实现原理 本篇我们来看看Android中的一些具体的跨进程通信的方式 使用Bundle 我们知道,四大组 ...

  2. Android中进程间通信(IPC)方式总结

    IPC为进程间通信或跨进程通信,是指两个进程进行进程间通信的过程.在PC和移动设备上一个进程指的是一个程序或者一个应用,所以我们可以将进程间通信简单理解为不同应用之间的通信,当然这种说法并不严谨. 在 ...

  3. Android中的IPC机制

    Android IPC简介 IPC是Inter-Process Communication的缩写,含义就是进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程.那么什么是进程,什么是线程,进程 ...

  4. Android中进程间通讯 AIDL

    Android中进程间通讯 AIDL IDL Interface Description Language  接口描述语言 AIDL Android IDL 适用场景:    client进程必须是A ...

  5. Android开发之IPC进程间通信-AIDL介绍及实例解析

    一.IPC进程间通信 IPC是进程间通信方法的统称,Linux IPC包括以下方法,Android的进程间通信主要采用是哪些方法呢? 1. 管道(Pipe)及有名管道(named pipe):管道可用 ...

  6. Android中使用SAX方式解析XML文件

    转载http://blog.csdn.net/cjjky/article/details/6666834 在Android中解析XML文主要有三种方式,分别为Simple API for XML(SA ...

  7. android 中xml解析方式

    2019独角兽企业重金招聘Python工程师标准>>> XML在各种开发中都广泛应用,Android也不例外.作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重 ...

  8. 关于Android中XML解析方式

    XML解析一般有三种方式:DOM .SAX.PULL. SAX解析器:它是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作.当事件源产生事件后,调用事件处理器相应的 ...

  9. android 通话结束广播,在Android中以编程方式结束通话

    侃侃尔雅 您无需成为系统应用程序.首先,com.android.internal.telephony在您的项目中创建包,并将其放入名为" ITelephony.aidl" 的文件中 ...

  10. 如何在android中设置背景,如何在Android中以编程方式设置背景可绘制

    MMTTMM layout.setBackgroundResource(R.drawable.ready);是正确的.实现它的另一种方法是使用以下方法:final int sdk = android. ...

最新文章

  1. windows下用GCC编译DLL
  2. 如何判断数组所有数都不等于一个数_【每日算法Day 91】求解数组中出现次数超过1/3的那个数
  3. centos安装zendopcache
  4. STL Vector使用例程
  5. ningbooj--1655--木块拼接(贪心)
  6. vivado烧写FPGA速度调节
  7. scrollview复用节点_利用ScrollView实现TableView效果(实现复用)
  8. Chapter 7:Statistical-Model-Based Methods
  9. 验证测试线时为什么会出现“正损耗”?
  10. 安利几个优质NLP开源项目!搜索、问答、情感分析…
  11. 正则表达式搜魂者(转:清清月儿 )
  12. Spring Boot Shiro权限管理--自定义 FormAuthenticationFilter验证码整合
  13. Mac删除Windows10后空间丢失解决
  14. 小论坛 之Linux服务器搭建Apache PHP mysql 环境
  15. 开源跨平台计算机视觉库OpenCV 4.0正式发布
  16. php计算工资的代码,php计算税后工资的方法_PHP
  17. 烤仔看世界 | “女王”的骗局
  18. JSON、AJAX、Maven
  19. 分布式事务之——两段式、三段式
  20. 12V转5V2A电源模块的电路集合

热门文章

  1. 3dmax材质通道插件_3dmax插件外挂神器【疯狂模渲大师蓝色经典版】第九章:渲染后期教程...
  2. ajax更换内容执行函数,在ajax成功调用另一个ajax函数
  3. php form表单提交代码,PHP之表单的提交
  4. Django:报错 unsupported format character ‘Y‘ (0x59) at index 70
  5. MySQL查询日期类数据常用函数
  6. ElementUI:设置table的背景透明、根据表格情况设置背景色、设置文字颜色、文字左右间距、表头、每一行高度
  7. TimeSpan asp.net中时间的运算
  8. 深度学习笔记_基本概念_逆卷积的详细解释ConvTranspose2d(fractionally-strided convolutions)
  9. 随手记_研究生怎样做学术
  10. 图像语义分割(4)-SegNet:深度全卷积编解码结构