美文网首页
Android关于aidl的理解

Android关于aidl的理解

作者: 海重山青 | 来源:发表于2018-03-14 16:33 被阅读0次

    原创博客地址

    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<Book> CREATOR = new Creator<Book>() {
            @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<Book> 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<Book> books;
    
        public MyAIDLService() {
        }
    
        private IBinder mIBinder = new IMyService.Stub() {
            @Override
            public void addBook(Book book) throws RemoteException {
                books.add(book);
            }
    
            @Override
            public List<Book> getBookList() throws RemoteException {
                return books;
            }
        };
    
        @Override
        public IBinder onBind(Intent intent) {
            books = new ArrayList<Book>();
            return mIBinder;
        }
    }   
    

    配置清单:

    <service
        android:name=".MyAIDLService"
        android:enabled="true"
        android:exported="true"
        android:process=":aidl"></service>
    
    • 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的理解

          本文链接:https://www.haomeiwen.com/subject/bqnfqftx.html