Android AIDL的基本使用

最近被公司调到了其他组,帮忙了一段时间Flutter,Android的东西落下了不少,还是打算继续从Framework方面继续学习。关于Android的IPC,之前也了解过,Binder的机制也可以说是研究过,但是由于不经常用,忘得也差不多了,现在连AIDL的基本使用都快忘了,更不用或Binder。所以这篇文章主要来介绍一下AIDL的基本使用。

一、服务端

服务端,也就是数据的提供方

第一步:创建一个实体类Book,要注意,Book要进行序列化的操作,也就是实现Parcelable接口

public class Book implements Parcelable {
    private int bookId;
    private String bookName;
    private double bookPrice;
    private List<String>bookShops;

    public Book(int bookId,String bookName,double bookPrice,List<String>bookShops){
        this.bookId = bookId;
        this.bookName = bookName;
        this.bookPrice = bookPrice;
        this.bookShops = bookShops;
    }

    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
        bookPrice = in.readDouble();
        bookShops = in.createStringArrayList();
    }

    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.writeInt(bookId);
        dest.writeString(bookName);
        dest.writeDouble(bookPrice);
        dest.writeStringList(bookShops);
    }

    public void readFromParcel(Parcel in){
        bookId = in.readInt();
        bookName = in.readString();
        bookPrice = in.readDouble();
        bookShops = in.createStringArrayList();
    }
}

第二步:创建两个AIDL文件:IBook和IBookManager。

IBook用于实体类Book的序列化声明,如下

// IBook.aidl
package com.example.bindertest;

parcelable Book;

IBookManager提供通信接口,用于通信代码的生成,注意:我们需要导入IBook这个类,如下:

// IBookManager.aidl
package com.example.bindertest;

import com.example.bindertest.IBook;

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

第三步:创建服务Service

在创建Service之前,我们先进行项目的Build操作,Android Studio会根据aidl文件IBookManager.aidl生成对应的java类IBookManager.java,然后创建IBookManager.Stub对象,也就是Service中onBind方法需要的IBinder对象,Service的代码如下:

public class BookService extends Service {
    private List<Book> bookList;

    private final IBookManager.Stub stub = new IBookManager.Stub() {
        @Override
        public List<Book> getBookList() throws RemoteException {
            return bookList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            if(book!=null){
                bookList.add(book);
            }else{
                Toast.makeText(BookService.this.getApplicationContext(), "数据异常", Toast.LENGTH_SHORT).show();
            }
        }
    };
    @Override
    public void onCreate() {
        super.onCreate();
        bookList = new ArrayList<>();
        initData();
    }

    private void initData(){
        List<String>bookShops = new ArrayList<>();
        bookShops.add("新华书店");
        bookShops.add("图灵书店");

        Book book1 = new Book(0,"《活着》",26f,bookShops);
        Book book2 = new Book(1,"《时间管理》",32f,bookShops);
        Book book3 = new Book(2,"《狼道》",45f,bookShops);

        bookList.add(book1);
        bookList.add(book2);
        bookList.add(book3);
    }

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

}

当然不要忘了在清单文件中对Service进行注册,如下

        <service
            android:name=".BookService"
            android:enabled="true"
            android:exported="true">
        </service>

第四步:启动Service

千万不要忘记启动Service,我使用了最简单的启动方法,在MainActivity中启动了服务:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startService(new Intent(this,BookService.class));
    }
}

二、客户端

第一步:进行相关文件的拷贝

我们重新创建一个项目或者Module作为客户端,将服务端的IBook.aidl,IBookManager.aidl,Book.java这三类拷入到客户端,要注意的是:路径一定要和服务端的路径一样,如下图所示

红框所示为服务端包名路径,而蓝框为客服端的包名路径,不要弄错了

 第二步:客户端进行连接,服务端数据的获取和修改,如下

public class MainActivity extends AppCompatActivity {
    private IBookManager bookManager;
    private boolean connected;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Toast.makeText(MainActivity.this, "服务链接成功", Toast.LENGTH_SHORT).show();
            bookManager = IBookManager.Stub.asInterface(service);
            connected = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Toast.makeText(MainActivity.this, "服务断开", Toast.LENGTH_SHORT).show();
            connected = false;
        }
    };

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

        //服务链接
        findViewById(R.id.service_con_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                //第一种方法
                intent.setClassName("com.example.bindertest","com.example.bindertest.BookService");
                //第二种方法
//                intent.setComponent(new ComponentName("com.example.bindertest","com.example.bindertest.BookService"));
                getApplicationContext().bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
            }
        });
        //解绑
        findViewById(R.id.service_discon_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getApplicationContext().unbindService(serviceConnection);
            }
        });
        //从服务端获取数据
        findViewById(R.id.get_book_list_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    List<Book> bookList = bookManager.getBookList();
                    for (Book book : bookList) {
                        Log.i("TAG",book.toString());
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        //修改服务端数据
        findViewById(R.id.add_book_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Book book = new Book(4,"《红人经济》",45,new ArrayList<>());
                try {
                    bookManager.addBook(book);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

要注意:进行服务连接时,要指定包名和类名

三、其他

aidl文件中有三个关键字:in,out,inout,这三个关键字,建议大家看这篇文章,说的很清楚,而我要说的是自己踩得坑:

如果在AIDL文件中的参数为in,则重写实体类中Parcelable的writeToParcel

如果在AIDL文件中的参数为out,则重写实体类中的readFromParcel

如果在AIDL文件中的参数为inout,以上两个方法都要重写

当然,默认是in,所以实现Parcelable接口就行了;而out和inout要额外注意一下

以上就是AIDL的基本使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值