Android知识点总结——AIDL的使用

1,096 阅读4分钟

定义

AIDL(Android Interface Definition Language)Android接口定义语言,主要帮助开发者完成进程间通信,我们知道Android中进程间通信有一种是Binder,AIDL就是帮助开发者简化Binder的一些操作,主动帮我们生成了需要Binder的代码。

AIDL所支持的数据类型

  • 基本数据类型
  • String以及Charsequence
  • List:只支持ArrayList,且里面的每个元素也必须是AIDL支持的类型
  • Map:只支持HashMap,且里面的每个元素也必须是AIDL支持的类型
  • Parcelable:支持java的对象,也就是javabean,但是要求该实体类必须实现Parcelable

使用步骤

既然是进程间通信,那么我们就新建两个项目aidlserver和aidlclient

aidlserver项目

  • 新建aidlserver项目,然后新建aidl文件夹
  • 在该文件夹下面新建Book.aidl类,(这个时候Android Studio会自动在与java同级的目录下面生成aidl文件夹,并且刚才新建的Book.aidl文件也在该目录下面)
  • 在aidl文件夹下面新建Book.java实体类,并且要实现Parcelable接口,复写里面的方法(注意不是AS为我们生成的aidl文件夹,而是在我们自己新建的aidl文件夹下面新建该实体类),这个时候该实体类是报错的
  • 实体类报错并不是我们代码写错了,修改Book.aidl,将系统为我们生成的代码改写为 parcelable Book;然后rebuild即可

  • 同样,在aidl文件夹下面新建IBookController.aidl文件,用来处理查找与添加的操作,在添加数据的时候这里由个tag要注意,也就是数据的流向。另外,操作实体类Book话要手动导包
package www.wfq.com.aidlserver.aidl;
import www.wfq.com.aidlserver.aidl.Book;

interface IBookController {
    List<Book> findAllBook();
    //新增一本书 使用定向tag inout
    // AIDL中的定向 tag 表示了在跨进程通信中数据的流向,其中
    // in 表示数据只能由客户端流向服务端,
    // out 表示数据只能由服务端流向客户端,
    // inout 则表示数据可在服务端与客户端之间双向流通
    void addBook(inout Book book);
}
  • 在aidl文件夹下面新建BookService,用来作为服务跟客户端通信
public class BookService extends Service {

    // 使用线程安全的CopyOnWriteArrayList
    private List<Book> books = new CopyOnWriteArrayList<>();
    private IBookController.Stub stub = new IBookController.Stub() {

        @Override
        public List<Book> findAllBook() throws RemoteException {
            return books;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            if (null != book) books.add(book);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        for (int i = 0; i < 5; i++) {
            books.add(new Book("book" + i));
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return stub;
    }
}
  • 如果想跟客户端通信的话还需要在清单文件中注册service,并且把exported = 'true',然后客户端访问的时候可以使用包名加action的形式进行连接
<service android:name=".aidl.BookService"
                 android:enabled="true"
                 android:exported="true">
            <intent-filter>
                <action android:name="www.wfq.com.aidiserver.aidl.BookService"></action>
                <category android:name="android.intent.category.DEFAULT"></category>
            </intent-filter>
        </service>
        

至此服务端编写完成,整体的目录结构如下图:

aidlclient项目

客户端项目的编写当对简单,步骤

  • 将服务端中Android Studio为我们生成的整个aidl文件夹拷贝到客户端,不要换包名,所在位置跟在服务端的位置一样(在拷贝文件夹的时候,可以将目录结构调整为Project模式)

  • 在客户端java文件夹下面新建aidl文件夹,整体的包名跟服务端保持一致,将服务端的Book.java这个实体类拷贝到该目录下。至此,文件拷贝工作完成
  • 编写代码,可在Activity中直接绑定服务端的service

public class MainActivity extends AppCompatActivity {

    private Button findBooks, addBook;
    private Boolean isConnected;
    private IBookController controller;
    private List<Book> bookList;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findBooks = findViewById(R.id.btn_get);
        addBook = findViewById(R.id.btn_add);
        bindService();
        findBooks.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    bookList = controller.findAllBook();
                    print();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });

        addBook.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    Book book = new Book("客户端新增一本书");
                    controller.addBook(book);
                    print();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });


    }

    private void print() {
        for (Book book : bookList) {
            Log.e("WFQ客户端", "value is: " + book);
        }

    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            isConnected = true;
            Log.e("WFQ客户端", "连接上服务");
            controller = IBookController.Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.e("WFQ客户端", "断开服务");
            isConnected = false;
        }
    };

    private void bindService() {
        Intent intent = new Intent();
        //设置服务端项目的包名
        intent.setPackage("www.wfq.com.aidlserver");
        //设置服务端在清单文件中注册服务时设置的action的值
        intent.setAction("www.wfq.com.aidiserver.aidl.BookService");
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    private void unBindService() {
        if (isConnected) unbindService(connection);
    }

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

代码以上传到github:

服务端代码:github.com/wfqdroid/ai…

客户端代码:github.com/wfqdroid/ai…