美文网首页
Android中AIDL的使用

Android中AIDL的使用

作者: hao_developer | 来源:发表于2023-07-20 14:33 被阅读0次

    AIDL,即Android Interface Definition Language,Android接口定义语言。这门语言是为了实现进程间通信。每一个进程都有自己的一块独立的内存,都在自己的内存上存储自己的数据,执行自己的操作,每个进程之间你不知我,我不知你,而AIDL,就是两个进程之间沟通的桥梁

    AIDL用来做什么

    AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definition language的缩写,对于小白来说,AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service,这样你的APP可以和其他APP交互。

    aidl文件支持的数据类型包括:

    八种基本数据类型:byte、char、short、int、long、float、double、boolean
    String、CharSequence
    实现了Parcelable接口的数据类型
    List类型。List承载的数据必须是AIDL支持的类型,或者是其他声明的AIDL对象
    Map类型。Map承载的数据必须是AIDL支持的类型,或者是其他声明的AIDL对象
    在使用其他声明的AIDL对象的时候必须要导包,即使要使用的AIDL对象文件和当前正在编辑的aidl文件在同一个文件夹下。

    aidl文件可以分为两类,一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用。

    AIDL的具体使用步骤是:

    一、创建一个服务端工程

    1、如果aidl文件中涉及到实现了Parcelable接口的数据类型,则先将该aidl文件定义出来。在src文件夹下右键,选择新建aidl文件,这里新建了一个Book.aidl文件。
    image.png

    新建完以后,会在main文件下生成一个aidl的文件夹,aidl文件夹下的目录结构和java文件夹下的目录结构一样


    image.png

    Book.aidl文件中会有一个默认方法。


    image.png
    我们删除掉这个默认方法,只声明一个parcelable数据类型,这个文件就成为声明Parcelable数据类型的AIDL文件。注意这里的parcelable中的p是小写的。
    image.png
    2、这个时候我们来定义Book类并实现Parcelable接口,\color{red}{注意Book类在java文件夹下的目录与Book.aidl文件在aidl文件夹下的目录保持一致}\
    
    public class Book implements Parcelable {
     
        private String name;
     
        public Book(String name) {
            this.name=name;
        }
     
        protected Book(Parcel in) {
            this.name = in.readString();
        }
     
        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];
            }
        };
     
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
     
        @Override
        public int describeContents() {
            return 0;
        }
     
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(name);
        }
     
        /**
         * 这个方法是自己写上去的,并不是根据错误提示自动生成的代码
         * 默认生成的模板类的对象只支持为in的定向tag。因为默认生成的类里面只有 writeToParcel() 方法。
         * 而如果要支持为out或者inout的定向tag的话,还需要实现readFromParcel()方法。
         * 而这个方法其实并没有在 Parcelable 接口里面,所以需要我们从头写。
         */
        public void readFromParcel(Parcel dest){
            name=dest.readString();
        }
    }
    
    这里需要注意的一点是如果要支持为out或inout的定向tag的话,需要我们手写readFromParcel()方法。
    3、然后我们开始写BookController.aidl文件来定义能被客户端调用的接口。
    
    package com.example.service;
     
    import com.example.service.Book;
     
    // Declare any non-default types here with import statements
     
    interface BookController {
     
        int getInt();//int类型
        String getString();//String类型
        List<Book> getBookList();//aidl对象
        void addBook(inout Book book);//aidl对象
     
    }
    
    这里需要注意的是,虽然Book.aidl文件和BookController.aidl文件在\color{red}{同一个包下}\,还是需要手动导入一下。
    4、至此,我们的aidl文件写完了,然后我们Rebuild project,系统会帮我们生成一个与AIDL文件同名的java文件,这个java文件才是与我们跨进程通信密切相关的东西。
    5、定义一个Service,通过这个Service将接口暴露给外部。
    
    public class AIDLService extends Service {
     
        private List<Book> bookList;
     
        public AIDLService() {
     
        }
     
        @Override
        public void onCreate() {
            super.onCreate();
            bookList = new ArrayList<>();
            initData();
        }
     
        private void initData() {
            Book book1 = new Book("花千骨");
            Book book2 = new Book("公主小妹");
            Book book3 = new Book("仙剑奇侠传");
            Book book4 = new Book("飘");
            Book book5 = new Book("茶花女");
            Book book6 = new Book("解忧杂货铺");
            Book book7 = new Book("活着");
            Book book8 = new Book("三生三世十里桃花");
            bookList.add(book1);
            bookList.add(book2);
            bookList.add(book3);
            bookList.add(book4);
            bookList.add(book5);
            bookList.add(book6);
            bookList.add(book7);
            bookList.add(book8);
        }
     
        private final BookController.Stub stub = new BookController.Stub() {
            @Override
            public int getInt() throws RemoteException {
                return bookList == null ? 0 : bookList.size();
            }
     
            @Override
            public String getString() throws RemoteException {
                return bookList == null ? "" : bookList.get(0).getName();
            }
     
            @Override
            public List<Book> getBookList() throws RemoteException {
                return bookList;
            }
     
            @Override
            public void addBook(Book book) throws RemoteException {
                if (book != null) {
                    bookList.add(book);
                } else {
                    Log.i("ruxing", "接收到了一个空对象 Inout");
                }
            }
        };
     
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return stub;
        }
    }
    
    6、在清单文件中注册服务。
    
      <service android:name=".AIDLService"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.example.service.action"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
            </service>
    

    至此,服务端开发完成了。

    二、创建一个custom工程

    1、新建一个custom工程,把服务端的aidl文件夹下的内容全部拷贝到新项目中,如果aidl中有用到bean实体类,把实体类也拷贝过来,然后Rebuild Project。
    image.png
    2、在客户端的activity中连接远程服务,实现aidl通信。
    
    public class MainActivity extends AppCompatActivity {
     
        private BookController bookController;
        private boolean connected;
        private List<Book> bookList;
     
        private Button mBtnGetBookList;
        private Button mBtnAddBook;
        private Button mBtnGetBookSize;
        private Button mBtnGetFirstBookName;
     
        private ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                bookController = BookController.Stub.asInterface(service);
                connected = true;
            }
     
            @Override
            public void onServiceDisconnected(ComponentName name) {
                bookController = null;
                connected = false;
            }
        };
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
     
            mBtnGetBookList = findViewById(R.id.btn_get_book_list);
            mBtnAddBook = findViewById(R.id.btn_add);
            mBtnGetBookSize = findViewById(R.id.btn_get_book_size);
            mBtnGetFirstBookName = findViewById(R.id.btn_first_book_name);
     
            mBtnGetBookList.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (connected) {
                        try {
                            bookList = bookController.getBookList();
                            for (int i = 0; i < bookList.size(); i++) {
                                Log.i("ruxing", "name=" + bookList.get(i).getName());
                            }
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            mBtnAddBook.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (connected) {
                        Book book = new Book("新书");
                        try {
                            bookController.addBook(book);
                            Log.i("ruxing", "向服务器添加了一本新书==="+book.getName());
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            mBtnGetBookSize.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (connected) {
                        try {
                            int size = 0;
                            size = bookController.getInt();
                            Log.i("ruxing", "共有" + size + "本书");
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            mBtnGetFirstBookName.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (connected) {
                        try {
                            String name = bookController.getString();
                            Log.i("ruxing", "第一本书的书名是:" + name);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
     
            Intent intent = new Intent();
            intent.setPackage("com.example.service");
            intent.setAction("com.example.service.action");
            bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
     
        }
     
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (connected) {
                unbindService(serviceConnection);
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Android中AIDL的使用

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