IPC机制之AIDL

什么是AIDL以及它的作用

AIDL指Android接口定义语言,是实现跨进程通讯的一种方式,可以让某一个Service与多个应用程序组件进行跨进程通讯,从而实现多个应用共享一个服务的功能,AIDL文件可以理解为客户端与服务端使用进程间通信进行互相通信时都认可的编程接口,只有允许不同应用的客户端用 IPC 方式访问服务,并且想要在服务中处理多线程时,才有必要使用 AIDL。

AIDL的基本用法

使用AIDL时有两个基本概念“客户端“和“服务端“,基本使用流程如下:

1 服务端创建AIDL文件,在AIDL文件中声明需要暴露给客户端的接口,创建一个服务用来监听客户端的连接请求,在服务中实现这个AIDL接口。
2 客户端绑定服务端的Service,将服务端返回的Binder对象转换为AIDL接口所属类型,接着就可以调用AIDL中定义的方法。
打开你的AS新建项目AIDLDemo,创建一个Module将它命名为Server,表示它是一个服务端,右击main打开目录如图
这里写图片描述
打开AIDL File 创建AIDL文件
这里写图片描述
点击Finish,Studio会自动为我们创建aidl文件夹,你定义的aidl文件也在此文件夹中
这里写图片描述
创建完AIDL文件后我们需要在aidl接口文件中声明需要暴露给客户端的方法

package com.tengfei.server;
import com.tengfei.server.Book;

interface IBookManager {
    List<Book> getBookList();
    void addBook(in Book book);
}

注意在这里使用到了实体类,如果你想在aidl中使用自定义类,那么该类必须实现Parcelable接口序列化,出于方便我们最好把跟aidl相关类定义在一起,那么使用到的Book类最好定义在和aidl文件的同级目录下并且序列化,同时新建与该类同名的aidl文件Book.aidl

// Book.aidl
package com.tengfei.server;

parcelable Book;

你的IBookManager文件如果需要用到Book类,那么必须显式的将Book类import进去
这里写图片描述
AIDL文件查创建成功后需要Rebuild一下才能自动帮我们生成代码,创建成功后会在build文件夹下生成如下所示文件
这里写图片描述
紧接着我们就需要在服务端中创建Service来供客户端调用,在Service中创建AIDL文件生成的Binder实例,并在onBind方法中返回该binder实例

public class BookManagerService extends Service {

    /**
     * CopyOnWriteArrayList实现了在遍历集合时也可以向集合中添加元素的作用
     */
    private CopyOnWriteArrayList<Book> bookCopyOnWriteArrayList = new CopyOnWriteArrayList<>();

    private Binder mBinder = new IBookManager.Stub() {
        @Override
        public List<Book> getBookList() throws RemoteException {
            return bookCopyOnWriteArrayList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            bookCopyOnWriteArrayList.add(book);
        }
    };


    @Override
    public void onCreate() {
        super.onCreate();
        bookCopyOnWriteArrayList.add(new Book(1, "Android"));
        bookCopyOnWriteArrayList.add(new Book(2, "IOS"));
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

到此为止服务端的AIDL已经创建成功了,不过需要注意的是无论是服务端还是客户端都需要在gradle文件的android闭包下声明如下代码

sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java.srcDirs = ['src/main/java', 'src/main/aidl']
            resources.srcDirs = ['src/main/java', 'src/main/aidl']
            aidl.srcDirs = ['src/main/aidl']
            res.srcDirs = ['src/main/res']
            assets.srcDirs = ['src/main/assets']
        }
    }

否则在编译时会报实体类找不到的错误,而这段代码的作用就是将aidl文件下的文件放到java集下编译。
接下来编辑客户端的代码,我们需要将服务端的aidl文件原封不动的复制到客户端,同样客户端也需要rebuild一下,核心代码如下:

public class MainActivity extends AppCompatActivity {

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IBookManager iBookManager = IBookManager.Stub.asInterface(service);
            try {
                List<Book> bookList = iBookManager.getBookList();
                Log.i("client", bookList.toString());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

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

    }

    public void bindService(View view) {
        Intent intent = new Intent();
        intent.setAction("com.tengfei.service.BOOK_MANAGER_AIDL");
        intent.setPackage("com.tengfei.server");
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

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

AIDL的调用过程

注意事项:

1 AIDL支持的数据类型:
基本数据类型、String、CharSequence
List:只支持ArrayList,里面的每个元素必须被AIDL支持
Map:只支持HashMap,里面的每个元素必须被AIDL支持
Parcelable : 实现Parcelable接口被序列化的类
所有的AIDL接口本身也可以在AIDL文件中使用
2 使用序列化的实体类:
自定义的Parcelable对象和AIDL对象,不管它们与当前的AIDL文件是否位于同一个包,都必须显式import进来,如果AIDL文件中使用了自定义的Parcelable对象,就必须新建一个和它同名的AIDL文件,并在其中声明它为Parcelable类型。

// Book.aidl
package com.tengfei.server;

parcelable Book;

3 AIDL接口中的参数除了基本类型以外都必须表明方向in/out。AIDL接口文件中只支持方法,不支持声明静态常量。建议把所有和AIDL相关的类和文件放在同一个包中,方便管理。

参考资料

Android开发艺术探索——读书笔记
Android官方中文文档

猜你喜欢

转载自blog.csdn.net/ku_tengfei/article/details/80331055
今日推荐