Android进程间通信AIDL的in、out、inout三种定向tag的使用

原创 2018年04月16日 17:46:33

AIDL定义

AIDL,全称Android Interface Definition Language,即Android接口定义语言。Android的一种进程间通信方式,同时也是Binder和Messager的底层。
在很多介绍aidl的文章中,都可以发现有三种定向tag:in、out、inout的使用,它们一般用于修饰aidl文件中的非基本类型参数。那么它们都是做什么用的呢?
经过本人一阵摸索,掌握了一些规律,分享出来,供大家参考~
- in: 默认方式;客户端将参数传给服务端使用,如同子弹,打出去就不管了~
- out:客户端将一个参数传给服务端,服务端将其作为容器,丢弃其中所有属性值后,再填充内容,然后还给客户端继续处理;如同一个盘子,服务端装满食物后,由客户端使用~
- inout:客户端将参数传给服务器,服务端可以使用参数的值,同时对这个参数进行修改,客户端会得到修改后的参数,如果是集合数组等,可修改其内部的子对象;如同客户端传给服务端一本书,服务端可以查看书中内容,也可以做一些笔记,然后还给客户端。
下面用代码演示~
1、首先看AIDL文件:

 // IBookManager.aidl
package com.example.wang.client.aidl;

import com.example.wang.client.bean.OrderBean;

interface IOrderManager {
    List<OrderBean> getAll();
    void add(in OrderBean bean);
    void getNameList(out String[] names);
    void updateIdList(inout String[] ids);
    void getOrder(out OrderBean bean);
    void updateOrder(inout OrderBean bean);
}
// OrderBean.aidl
package com.example.wang.client.bean;
parcelable OrderBean;

2、OrderBean类

package com.example.wang.client.bean;
...
public class OrderBean implements Parcelable{
    private String id;
    private String name;
    private int amount;

    public OrderBean(){}

    public OrderBean(String id, String name, int amount) {
        this.id = id;
        this.name = name;
        this.amount = amount;
    }

    protected OrderBean(Parcel in) {
        id = in.readString();
        name = in.readString();
        amount = in.readInt();
    }

    public static final Creator<OrderBean> CREATOR = new Creator<OrderBean>() {
        @Override
        public OrderBean createFromParcel(Parcel in) {
            return new OrderBean(in);
        }

        @Override
        public OrderBean[] newArray(int size) {
            return new OrderBean[size];
        }
    };

    //省略get/set方法

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(id);
        dest.writeString(name);
        dest.writeInt(amount);
    }
    public void readFromParcel(Parcel in){
        id = in.readString();
        name = in.readString();
        amount = in.readInt();
    }

    @Override
    public String toString() {
        String string = "OrderBean{id:"+id+",name:"+name+",amount:"+amount+"}";
        return string;
    }
}

3、客户端绑定代码

//MainActivity.java
package com.example.wang.client;
...

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private List<OrderBean> orderList;
    private IOrderManager orderManager;
    //UI细节省略
    ...
    //连接远程service
    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IOrderManager manager = IOrderManager.Stub.asInterface(service);
            orderManager = manager;
            refreshOrderList();
            ...
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //UI相关代码略过
        ...
        //bind
        bindOrderService();
    }
    private void bindOrderService(){
        Intent intent = new Intent("com.example.wang.ordermanager.OrderService");
        intent.setPackage("com.example.wang.ordermanager");
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onClick(View v) {
        if(v==search_button){
            //重点看这里
            try {
                //测试out方式,传递数组
                String[] names={"老虎","狮子","大象","骆驼"};
                orderManager.getNameList(names);
                Log.i("MainActivity","@@ 刷新订单 names="+ Arrays.toString(names));
                //测试inout方式,传递数组
                String[] ids={"a1","b2","c3","b4"};
                orderManager.updateIdList(ids);
                Log.i("MainActivity","@@ 刷新订单 ids="+ Arrays.toString(ids));
                //测试out方式,传递Parcelable对象
                OrderBean order1=new OrderBean("123","降龙十八掌",3456);
                orderManager.getOrder(order1);
                Log.i("MainActivity","@@ 刷新订单 order1 -> "+order1.toString());
                //测试inout方式,传递Parcelable对象
                OrderBean order2=new OrderBean("456","独孤九剑",6789);
                orderManager.updateOrder(order2);
                Log.i("MainActivity","@@ 刷新订单 order2 -> "+order2.toString());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            refreshOrderList();
        }else if(v==add_button){
            //增加订单,使用in方式
            try {
                OrderBean orderBean=new OrderBean();
                Random random=new Random();
                orderBean.setAmount(random.nextInt(800)+100);
                orderBean.setId(random.nextInt(100000000)+100000+"");
                orderBean.setName("玩具"+random.nextInt());
                orderManager.add(orderBean);
                refreshOrderList();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

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

4、服务端service代码:

//OrderService.java
package com.example.wang.ordermanager;
...
public class OrderService extends Service{
    private CopyOnWriteArrayList<OrderBean> list = new CopyOnWriteArrayList<>();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("OrderService","@@ onBind");
        return binder;
    }

    Binder binder = new IOrderManager.Stub(){

        @Override
        public List<OrderBean> getAll() throws RemoteException {
            return list;
        }

        @Override
        public void add(OrderBean bean) throws RemoteException {
            bean.setId(bean.getId()+"_ii");
            bean.setName(bean.getName()+"_nn");
            bean.setAmount(bean.getAmount()+50000);
            Log.i("OrderService","@@ add bean="+ bean.toString());
            list.add(bean);
        }

        @Override
        public void getNameList(String[] names) throws RemoteException {
            Log.i("OrderService","@@ getNameList names="+ Arrays.toString(names));
            names[0]="苹果";
            names[1]="香蕉";
            names[2]="榴莲";
        }

        @Override
        public void updateIdList(String[] ids) throws RemoteException {
            Log.i("OrderService","@@ setIdList names="+ Arrays.toString(ids));
            ids[0]=ids[0]+"_11";
            ids[1]=ids[1]+"_22";
            ids[2]=ids[2]+"_33";
        }

        @Override
        public void getOrder(OrderBean bean) throws RemoteException {
            Log.i("OrderService","@@ updatePrice "+bean.toString());
            bean.setId(bean.getId()+"-12345");
            bean.setName(bean.getName()+"-九阴真经");
            bean.setAmount(bean.getAmount()+10000);
        }

        @Override
        public void updateOrder(OrderBean bean) throws RemoteException {
            Log.i("OrderService","@@ updateOrder id="+bean.toString());
            bean.setId(bean.getId()+"-98765");
            bean.setName(bean.getName()+"-葵花宝典");
            bean.setAmount(bean.getAmount()+20000);
        }
    };
}

5、查看输出结果:

//in方式
04-16 17:24:01.648 31198-31229/com.example.wang.ordermanager I/OrderService: @@ add bean=OrderBean{id:43788467_ii,name:玩具1186168941_nn,amount:50731}
04-16 17:24:01.649 31279-31279/com.example.wang.client I/MainActivity: @@ 增加订单 order1 -> OrderBean{id:43788467,name:玩具1186168941,amount:731}
//out方式,数组参数
04-16 17:24:05.602 31198-31211/com.example.wang.ordermanager I/OrderService: @@ getNameList names=[null, null, null, null]
04-16 17:24:05.603 31279-31279/com.example.wang.client I/MainActivity: @@ 刷新订单 names=[苹果, 香蕉, 榴莲, null]
//inout方式,数组参数
04-16 17:24:05.611 31198-31229/com.example.wang.ordermanager I/OrderService: @@ setIdList names=[a1, b2, c3, b4]
04-16 17:24:05.612 31279-31279/com.example.wang.client I/MainActivity: @@ 刷新订单 ids=[a1_11, b2_22, c3_33, b4]
//out方式,Parcelable参数
04-16 17:24:05.613 31198-31210/com.example.wang.ordermanager I/OrderService: @@ updatePrice OrderBean{id:null,name:null,amount:0}
04-16 17:24:05.614 31279-31279/com.example.wang.client I/MainActivity: @@ 刷新订单 order1 -> OrderBean{id:null-12345,name:null-九阴真经,amount:10000}
//inout方式,Parcelable参数
04-16 17:24:05.615 31198-31211/com.example.wang.ordermanager I/OrderService: @@ updateOrder id=OrderBean{id:456,name:独孤九剑,amount:6789}
04-16 17:24:05.616 31279-31279/com.example.wang.client I/MainActivity: @@ 刷新订单 order2 -> OrderBean{id:456-98765,name:独孤九剑-葵花宝典,amount:26789}

通过输出结果可以发现:
1. 使用in方式时,参数值单向传输,客户端将对象传给服务端后,依然使用自己的对象值,不受服务端的影响。
2. 使用out方式传递数组类型时,客户端传递给服务端的只有数组的长度,客户端得到的是服务端赋值后的新数组。
3. 使用inout方式传递数组类型时,客户端会将完整的数组传给服务端,客户端得到的是服务端修改后的数组。
4. 使用out方式传递Parcelable对象时,客户端传给服务端的是一个属性值全部为空的对象,得到的是服务端重新赋值后的对象。
5. 使用inout方式传递Parcelable对象时,客户端会将完整的对象传递给服务端,得到的是服务端修改后的对象。

探索AIDL定向tag in out inout原理

上一篇文章《从一个例子开始分析AIDL原理》分析了通过AIDL来完成跨进程通信的过程,文章最后抛出了一个问题: aidl语法中参数列表中的定向tag: in、out 和 inout 是什么含义?(阅读...
  • jdqm2014
  • jdqm2014
  • 2017-10-17 18:48:30
  • 180

关于aidl参数方向in,out,inout网上的解释

in类型类型是值传递,而out类型类型是引用传递。http://blog.csdn.net/jdsjlzx/article/details/7182048 AIDL中的定向 tag 表示了在跨进程通...
  • u013634928
  • u013634928
  • 2016-11-10 09:50:21
  • 289

Android远程接口之AIDL——Parcelable、in、out、inout简例

AIDL简义 Android中的数据传输、方法调用等,常见的是集中在应用程序内的Activity之间,如Activity-A传递到Activity-B。 这样的数据传输、方法等都是在一个应用程序间...
  • yangzhaomuma
  • yangzhaomuma
  • 2016-01-25 00:21:30
  • 7231

你真的理解AIDL中的in,out,inout么?

前言这其实是一个很小的知识点,大部分人在使用AIDL的过程中也基本没有因为这个出现过错误,正因为它小,所以在大部分的网上关于AIDL的文章中,它都被忽视了——或者并没有,但所占篇幅甚小,且基本上都是官...
  • luoyanglizi
  • luoyanglizi
  • 2016-07-19 17:51:06
  • 13220

AIDL中的定向tag

AIDL中的定向 tag 表示了在跨进程通信中数据的流向,其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通...
  • qq_27840621
  • qq_27840621
  • 2017-05-04 12:46:35
  • 266

关于Android中aidl的关键词in,out,inout的探索

第一问:aidl是啥 aidl是 Android Interface definition language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进...
  • yunjiawei1
  • yunjiawei1
  • 2017-10-31 11:22:38
  • 166

Android AIDL之in out inout

Android AIDL之in out inout可能很多人会不清楚定义aidl接口到底如何定义为好,这里还是总结一下,毕竟笔记是最深刻的理解。一、aidl支持哪些数据类型呢? Java 编...
  • xutao123111
  • xutao123111
  • 2016-12-20 13:27:35
  • 233

AIDL 学习Demo,包含定向Tag,序列化信息通讯。

  • 2017年12月01日 18:05
  • 30.86MB
  • 下载

Android多进程间采用AIDL方式进行通信简单DEMO

在上一节中,我介绍了Android中Service的生命周期以及一些有关知识。在这一节中,我采用代码编写的方式来介绍一下不同程序之间也就是不同进程之间通信采用AIDL方式。 首先我需要解释一下,不同...
  • ligangying
  • ligangying
  • 2015-10-28 13:26:47
  • 1118

AIDL中in,out和inout的区别

in:只能在客户端设置值,传入服务端,服务端获取客户端设置的值 out:用于在服务端设置值,服务端设置这个值后,客户端也可以得到这个由服务端设置的值,客户端如果有设置初始值,到了服务端会得不到这个值 ...
  • LAMP_zy
  • LAMP_zy
  • 2016-06-02 15:24:22
  • 1249
收藏助手
不良信息举报
您举报文章:Android进程间通信AIDL的in、out、inout三种定向tag的使用
举报原因:
原因补充:

(最多只允许输入30个字)