Android开发——进程间通信之AIDL(二)

0.  前言

不论是Android还是其他操作系统,都会有自己的IPC机制,所谓IPCInter-Process Communication)即进程间通信。首先线程和进程是很不同的概念,线程是CPU调用的最小单元,进程一般在PC和移动设备上指一个程序或者一个应用,一个进程可以包含多个线程。

IPC方式有很多,在Android中常用的IPC方式包括Bundle、文件、MessengerAIDLContentProviderSocket等方式Android开发——进程间通信之AIDL(一)中介绍了AIDL的一个简单的用法,本篇主要讲解使用AIDL传递自定义对象的方式。

 

1.  序列化

aidl文件定义的接口支持的数据类型如下:

//1.Java的八种基本数据类型(byte,int,short,long,float,double,char,boolean)
//2.String
//3.CharSequence
//4.List,List中所有的元素必须是aidl文件支持的数据类型,例如List<String>
//5.Map,Map中所有的元素必须是aidl文件支持的数据类型,
//6.其他aidl定义的接口,要手动添加import
//7.其他aidl文件中申明的类,要手动添加import

Android开发——进程间通信之AIDL(一)中的远程加法器中,我们传递的就是int型数据,这篇主要介绍最后一种,其他aidl文件中申明的类,这个类可以是自定义的类,因此传递的数据类型组合更加自由。但是自定义的类要完成IPC必须要序列化,序列化有SerializableParcelable两种方法,后者是Android中的序列化方式,因此效率更高,但是使用起来比较麻烦。

先看一下完整工程的目录结构:

Person.java就是我们自定义的类。我们要实现的目的就是跨进程传递该对象的内容。首先实现该类的序列化。

package com.example.ipc_aidl_obj;
/**
 * Java Bean
 * Created by SEU_Calvin on 2017/3/25.
 */
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable{
    private String name;
    private int age;
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    //从Parcel中读出之前写进的数据
    protected Person(Parcel in) {
        this.name = in.readString();
        this.age = in.readInt();
    }
    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
        //反序列化,把我们通过writeToParcel方法写进的数据再读出来
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }
        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    //实现 Parcelable 接口所需重写的方法1,一般不用管
    @Override
    public int describeContents() {
        return 0;
    }
    //实现 Parcelable 接口所需重写的方法2,将对象的每个字段写入到Parcel中
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
    }
    @Override
    public String toString() {
        return "Person{" +"name='" + name + '\'' +", age=" + age +'}';
    }
}

我们的Person实现了Parcelable接口,覆写了接口中describeContents()writeToParcel() 的两个方法,前者返回当前对象的内容描述,如果有描述符则返回1,绝大多数情况要返回0。后者将对象写入序列化结构中。通过查看文档我们发现Parcel是没有writeShort()这个方法的,这也正是AIDL无法传递short类型的数据的原因。然后就是静态创建构造器CREATOR,注意要加final修饰且名字必须为CREATOR不能更改,其中createFromParcel()用于把我们之前写进Parcel中的数据在读出来。这里要注意的是哪个字段先写进去,就先读取哪个字段。这样我们自定义的实体类就序列化好了,以备后续使用。

2.   创建AIDL文件

共有两个AIDL文件,一个是我们自定义对象的声明,一个是接口声明。在后者中需要将前者显式的import进来。

// IPersonn.aidl
package com.example.ipc_aidl_obj;
// Declare any non-default types here with import statements
parcelable Person;

// IGetData.aidl
package com.example.ipc_aidl_obj;
// Declare any non-default types here with import statements
import com.example.ipc_aidl_obj.Person;
interface IGetData{
    List<Person> getPersonList(in Person person);
}

接口中的getPersonList()方法将客户端传来的Person对象放入List中并返回List中全部的对象,这里需要说一下的就是getPersonList()方法中的in关键字,即数据的走向,有in/out/inout三种类型。根据需求选择合适的的数据走向类型。

3.   实现接口

package com.example.ipc_aidl_obj;
/**
 * 服务端
 * Created by SEU_Calvin on 2017/3/25.
 */
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;

public class IRemoteService extends Service {
    List<Person> persons;
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        persons = new ArrayList<>();
        return iBinder;
    }

    private IBinder iBinder = new IGetData.Stub() {
        @Override
        public List<Person> getPersonList(Person person) throws RemoteException {
            persons.add(person);
            return persons;
        }
    };
}

该服务端运行在独立进程,主要是对AIDL接口中的方法进行了实现。

 

4.   客户端调用

首先进行服务的绑定。并在ServiceConnection的回调方法中获得服务端返回的Binder实例。

Intent intent = newIntent(MainActivity.this,IRemoteService.class);
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
 
private ServiceConnection serviceConnection = newServiceConnection() {
        @Override
        public voidonServiceConnected(ComponentName name, IBinder service) {
            mGetData =IGetData.Stub.asInterface(service);
        }
        @Override
        public voidonServiceDisconnected(ComponentName name) {
        }
};

当点击按钮后,即可远程调用获得的IgetData对象的getPersonList()方法,将一个初始化好的Person类对象作为参数传入,将返回的List中的Person实例的内容全部Toast出来,这里点击了四次,添加了四个Person以及其年龄信息(亲爱的东大114岁了,Android6岁,我永远18岁QAQ),效果如下,这样整个客户端和服务端的自定义对象跨进程传递的过程就使用AIDL完成了。

参考源码地址点击下载请大家多点赞支持~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值