Android关于aidl的理解

原创博客地址

AIDL简介

Android中,进程之间原则上是不能进行通信的。但偏偏Android从四大组件到框架、底层到处都是IPC的影子。AIDL就是IPC方式之一。

AIDLAndroid 接口定义语言) 是 Android 提供的一种进程间通信 (IPC) 机制。

我们可以使用它在两个不同进程之间ClientServer进行通信

使用AIDL步骤

使用aidl大致分为三块,编写aidl生成必要文件。创建ClientServer使用。

  • 编写AIDL
    • 创建Bean类,实现Parcelable接口(便于序列化反序列化)。
    • 编写aidl文件
    • 生成java文件
  • 编写Server
    • 创建 Service,在其中创建上面生成的 Binder 对象实例,实现接口定义的方法
    • onBind()中返回
  • 编写Client
    • 实现 ServiceConnection 接口,在其中拿到 AIDL
    • 绑定服务
    • 调用aidl中的请求并等待返回结果

步骤一:编写AIDL

  • 创建Bean类,实现Parcelable接口(便于序列化反序列化
package com.cx.aidldemo.bean;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * 书的实体类
 */
public class Book implements Parcelable {

    private String name;
    private double price;

    public Book() {}

    public Book(String name, double price) {
        this.name = name;
        this.price = price;
    }

    protected Book(Parcel in) {
        name = in.readString();
        price = in.readDouble();
    }

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

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

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeDouble(price);
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}
  • 编写aidl文件

    • 不过在编写aidl文件之前,要拥有aidl目录。没有的话就创建。
    • 创建方式:在main目录下创建aidl目录,并在aidl目录下创建和java目录下子目录一样的包名。
aidl包名一致.png
  • 创建Bean类的aidl
// Book.aidl
package com.cx.aidldemo.bean;

parcelable Book;
  • 创建接口的aidl
// IMyService.aidl
package com.cx.aidldemo;

import com.cx.aidldemo.bean.Book;

interface IMyService {

    /**
     * 添加一个书
     */
    void addBook(in Book book);

    /**
     * 获取所有书
     */
    List getBookList();
}

注意:

  1. 这个 Book.aidl 的包名要和实体类包名一致。
  2. 除了基本数据类型,其他类型的参数都需要标上方向类型:in(输入),out(输出),inout(输入输出)。
  3. 非基本类型的数据需要导入它的全路径。即便是同级目录下。
  • 生成java文件
    • 方式:Build -> Make Project
    • 然后就会在app/build/generated/source/aidl/package_name/ 下生成一个 Java 文件
生成java文件.png

现在我们就可以通过它来进行IPC通信了。

步骤二:编写Server

  • 创建 Service,在其中创建上面生成的 Binder 对象实例,实现接口定义的方法
  • onBind()中返回
public class MyAIDLService extends Service {

    private List books;

    public MyAIDLService() {
    }

    private IBinder mIBinder = new IMyService.Stub() {
        @Override
        public void addBook(Book book) throws RemoteException {
            books.add(book);
        }

        @Override
        public List getBookList() throws RemoteException {
            return books;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        books = new ArrayList();
        return mIBinder;
    }
}   

配置清单:


  • enabled属性
    • 默认为true
    • 其值为true,则说明应用程序组件可以被Android系统自动实例化
    • 如果为false,则说明实例化组件的工作需要手工完成。
  • exported属性
    • 是否支持其它应用调用当前组件
    • 如果包含有intent-filter 默认值为true;没有intent-filter默认值为false
  • process属性
    • 如果该属性里设置的名字以冒号开头(:),那么在需要的时候它将生成该应用程序的一个私有新进程

服务端实现了接口,在 onBind() 中返回这个 Binder,客户端拿到就可以操作数据了。

步骤三:编写Client

  • 实现 ServiceConnection 接口,在其中拿到 AIDL
public class MainActivity extends AppCompatActivity {

    private IMyService iMyService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // onBind连接后会返回 Binder,也就是iBinder参数
            // 将其转换成 AIDL,在不同进程会返回代理对象
            iMyService = IMyService.Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            iMyService = null;
        }
    };
}
  • 绑定服务
Intent intent1 = new Intent(getApplicationContext(), MyAIDLService.class);
// 绑定服务
bindService(intent1, connection, BIND_AUTO_CREATE);
  • 调用aidl中的请求并等待返回结果
/**
 * 添加一本书
 * @param view
 */
public void onAddBook(View view) {
    Book book = new Book("Android_" + System.currentTimeMillis(), 100);
    try {
        iMyService.addBook(book);
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

/**
 * 获取所有书籍
 * @param view
 */
public void onGetBooks(View view) {
    try {
        tvResult.setText(iMyService.getBookList().toString());
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

日志打印:

服务端进程名.png

客户端进程名.png

运行结果:

运行结果.gif

源码Demo下载地址

你可能感兴趣的:(Android关于aidl的理解)