Android AIDL实践

来源:互联网 发布:数据nbastat 编辑:程序博客网 时间:2024/06/05 17:09

在Android中用到进程之间的通信(IPC)最常用的方式就是使用AIDL了,网上关于AIDL的介绍已经很多了,这篇文章主要记录下AIDL的使用方法。

这里声明了两个工程,分别模拟客户端与服务端。项目如下所示,BinderClient为客户端,BinderService为服务端。

进行进程之间的通信,那么进程之间通信的对象就必须进行处理,一般来说将自定义的对象实现Parcelable接口,完成序列化与反序列化的操作。代码如下所示,

package com.vic.aidl;import android.os.Parcel;import android.os.Parcelable;public class Book implements Parcelable{private int id;private String name;public Book(int id, String name) {super();this.id = id;this.name = name;}public Book(Parcel in){id = in.readInt();name = in.readString();}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(id);dest.writeString(name);}public static Parcelable.Creator<Book> CREATOR = new Creator<Book>() {@Overridepublic Book[] newArray(int size) {return new Book[size];}@Overridepublic Book createFromParcel(Parcel source) {return new Book(source);}};@Overridepublic String toString() {return "Book [id=" + id + ", name=" + name + "]";}}
这里Book类中writeToParcel为序列化操作,而在CREATOR中完成了反序列化的操作。

声明好Book类后还需要建立一个Book.aidl文件,在里面显示引用Book类所在的包名,与用pacelabel声明Book类为一个可序列化的对象,代码如下所示

package com.vic.aidl;parcelable Book;
对Book对象进行操作完毕后,我们就需要声明一个aidl接口来完成服务端提供给客户端所调用的方法,在这里服务端为客户端提供了两个方法,一个是addBook(in Book book),一个是void getBookList()。需要注意的是在addBook(in Book book)中的in,表示这是一个输入参数 ,对应的还有our输出参数,inout输入输出参数。详细的代码如下

package com.vic.aidl;import com.vic.aidl.Book;interface IBookService{void addBook(in Book book);List<Book> getBookList();}
到此为止服务端aidl所需要的类就提供完毕了,目前服务端还需要一个Service来实现aidl所声明的方法。这里定义了一个BookManagerService类,代码如下

package com.vic.service;import java.util.ArrayList;import java.util.List;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import com.vic.aidl.Book;import com.vic.aidl.IBookService;public class BookManagerService extends Service{private List<Book> mBookList = new ArrayList<Book>();public Binder mBinder = new IBookService.Stub(){@Overridepublic void addBook(Book book) throws RemoteException {mBookList.add(book);}@Overridepublic List<Book> getBookList() throws RemoteException {Log.d("MLJ","BookManagerService#getBookList()");return mBookList;}};public void onCreate() {Log.d("MLJ","BookManagerService#onCreate()");mBookList.add(new Book(1,"ios"));mBookList.add(new Book(2,"android"));};@Overridepublic IBinder onBind(Intent intent) {return mBinder;}}
Service启动的时候在List里面添加了2本书,并在onBind绑定的时候返回了Binder对象,这样就可以为客户端提供Binder对象来调用服务端里面实现的方法了。IBookService.Stub()方法,就是返回一个Binder对象。这个类具体的实现可以参考gen/com.vic.aidl.IBookService.java。这个类是由系统自动生成的,主要作用是提供了一个Binder类为服务器与客户端的通信提供了桥梁。

最后再将服务端的项目结构列出来,


服务端的工作完成后,下面就来完成客户端的实现,新建一个工程BinderClient,值得注意的是,我们需要将服务端com.vic.aidl包中的文件一齐拷入到客户端,不拷入的话客户端遍无法通过Binder调用服务端中的方法了。客户端的项目结构如下所示

有了服务端,客户端的实现就比较简单了。代码如下所示,客户端中有3个button分别对用绑定服务端,添加一本书,以及获取list的集合。

package com.vic.client;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import com.vic.aidl.Book;import com.vic.aidl.IBookService;public class BinderClientActivity extends Activity{private Button mButtonConnect = null;private Button mButtonAdd = null;private Button mButtonGet = null;private static final String SERVICE_NAME = "com.vic.service.BookManagerService";private IBookService mBookService = null;private ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.d("MLJ","BinderClientActivity#onServiceConnected()");mBookService = IBookService.Stub.asInterface(service);try {Log.d("MLJ","book list=" + mBookService.getBookList());} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mButtonConnect = (Button) findViewById(R.id.button_connect);mButtonAdd = (Button) findViewById(R.id.button_add);mButtonGet = (Button) findViewById(R.id.button_get);mButtonConnect.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent i = new Intent(SERVICE_NAME);            <span style="white-space:pre"></span>i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  bindService(i, conn, Context.BIND_AUTO_CREATE);startService(i);  //如果只是不调用这句话,后台不会显示Service进程}});mButtonAdd.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {try {mBookService.addBook(new Book(mBookService.getBookList().size()+1,"new book" + (mBookService.getBookList().size()+1)));} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});mButtonGet.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {try {Log.d("MLJ","book list=" + mBookService.getBookList());} catch (RemoteException e) {e.printStackTrace();}}});}}
点击连接按钮,返回当前服务端List<Book>,可以看到客户端已经可以接收到当前服务端中的数据了

然后在点击添加按钮后,在点击获取当前list,可以看到日志返回如下所示

我们可以看到添加的书籍也可以从客户端成功的返回了。

总结:要通过AIDL进行通信,步骤是

1. 自定义的类需要实现Pacelabel接口的方法。

2. 自定义的类需要声明一个自定义类所对应的aidl文件,在文件中将包名显示引入,并用pacelabel关键字修饰自定义对象。

3. 提供一个服务端的aidl接口

4. 在服务端里通过Binder实现这个aidl接口。

5. 客户端获取Binder,并通过binder来操作服务端中提供的接口,与服务端进行通信。

好了,AIDL的简单实用方法就介绍到这里,以后会再介绍一些AIDL的使用难点,比如AIDL中对接口的注销,以及服务的重新绑定等等。

点我下载demo

1 0
原创粉丝点击