IPC机制第二篇,AIDL实现

好久之前,就想学习一下AIDL了,网上找了好多资料,都是特别的零乱,今天终于调出第一个AIDL的Demo,耐不住心中的激动,立刻来这边写篇文章巩固一下。

AIDL和Messenger一样是解决进程间通信的方法,而且Messenger的底层实现也是通过AIDL所以说AIDL是爸爸,恩,是可以这么理解。那爸爸肯定比儿子厉害,下面来说说AIDL的优势。Messenger主要用于进程间传递消息,但是如果要做到客户端调用服务器的方法,那Messenger就做不到了,AIDL这时候就派上用场了。但是一般简单的详细传递就建议用Messenger毕竟这个方法简单。好下面上代码了。

建一个工程,名字就叫做AIDLDemo。
首先准备接口IBookManager.aidl

// IBookManager.aidl
package com.zafu.aidldemo;

// Declare any non-default types here with import statements
import com.zafu.aidldemo.Book;

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

由于Book是自定义类型,所以要实现Parcelable序列化接口,AndroidStudio对Parcelable支持还是很好的,你只要下个插件直接自动生成代码,这个具体自己查百度吧

Book.java

public class Book implements Parcelable {
    public int bookId;

    @Override
    public String toString() {
        return "Book{" +
                "bookId=" + bookId +
                ", bookName='" + bookName + '\'' +
                '}';
    }

    public String bookName;

    public Book(int bookId, String bookName){
        this.bookId = bookId;
        this.bookName = bookName;
    }


    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = 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];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(bookName);
    }
}

接口做好了吗?不!还没有,还有个文件Book.aidl

// Book.aidl
package com.zafu.aidldemo;

// Declare any non-default types here with import statements
parcelable Book;

到这里,接口就真的做好了。这里有几个注意事项说一下IBookManager.aidl文件中只要用了自定义类型或是AIDL类,就要手动import,这里用AndroidStudio有点蛋疼,他的支持并不是特别好没有提示,但是不这样做程序就会报错。
 
终于送了口气,下面我们来写一下服务器端代码
BookManagerService.java

public class BookManagerService extends Service {

    private CopyOnWriteArrayList<Book> mBookList =  new CopyOnWriteArrayList<Book>();

    public BookManagerService() {
    }
    private Binder mBinder = new IBookManager.Stub(){

        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }

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

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

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

在清单文件里面分出一个进程实现多进程通信

         <service
            android:process=":remote"
            android:name=".BookManagerService"
            android:enabled="true"
            android:exported="true"></service>

客户端的代码比较简单MainActivity.java

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private ServiceConnection mConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IBookManager iBookManager = IBookManager.Stub.asInterface(service);
            try {
                List<Book> bookList = iBookManager.getBookList();
                Log.i(TAG, "query book list, list type: " +
                bookList.getClass().getCanonicalName());
                Log.i(TAG, "query book list: " + 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);
        Intent intent = new Intent(this, BookManagerService.class);
        bindService(intent, mConn, Context.BIND_AUTO_CREATE);
    }
}

就这么粗暴,Demo写好了。总结一下,在服务器端开一个服务,与客户端通过Binder实现通信.

这里有两个注意点:
1. AIDL方法是在服务器端的Binder线程池中执行的,因此当多个客户端同时连接的时候,会存在多个线程同时访问的情形,所以我们要在AIDL方法中处理线程同步,而我们这里直接使用CopyOnWriteArrayList来进行自动的线程同步,类似的还有ConcurrentHashMap
2. 服务器的方法有可能需要很久才能执行完毕,这个时候在客户端上调用,可能会出现ANR,需要多线程编程
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值