Android中的IPC方式——使用AIDL
来源:互联网 发布:心理学本科网络教育 编辑:程序博客网 时间:2024/06/10 16:47
上一篇博文介绍了使用Messenger来进行IPC,可以发现Messenger是以串行的方式处理客户端发来的消息,如果有大量的消息发过来只能一个一个的处理,就先的不太合适。这篇博文介绍使用AIDL进行进程间通信,使用IPC。
AIDL的大概实现过程如下
1、服务端
服务端首先要创建一个Service用来坚挺客户端的链接请求,然后创建一个AIDL文件,将暴露给客户端的接口在合格AIDL文件中声明,然后在Service中实现这个AIDL接口即可。
2、客户端
客户端所要做的事情就稍微简单点,首先需要绑定服务端的Service,绑定成功后,将服务端返回的Binder对象转成AIDL接口所属的类型,接着调用AIDL中的方法就可以了。
工程目录:
首先创建一个IBookManager.aidl
package com.qian.aidlipc;import com.qian.aidlipc.Book;interface IBookManager { List<Book> getBookList(); void addBook(in Book book);}
在aidl文件中声明了两个方法,这两个方法就是暴露给客户端的,我们需要服务端实现。另外上面的aidl文件还用到了Book这个类,所以也要创建Book.aidl,然后添加如下内容
package com.qian.aidlipc;parcelable Book;
Book.java是一个实体类,继承了Parcelable,可序列化
package com.qian.aidlipc;import android.os.Parcel;import android.os.Parcelable;public class Book implements Parcelable { public int bookId; public String bookName; public Book() { } public Book(int bookId, String bookName) { this.bookId = bookId; this.bookName = bookName; } public int describeContents() { return 0; } public void writeToParcel(Parcel out, int flags) { out.writeInt(bookId); out.writeString(bookName); } public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() { public Book createFromParcel(Parcel in) { return new Book(in); } public Book[] newArray(int size) { return new Book[size]; } }; private Book(Parcel in) { bookId = in.readInt(); bookName = in.readString(); } @Override public String toString() { return String.format("[bookId:%s, bookName:%s]", bookId, bookName); }}
3、远程服务端Service的实现
上面定义了AIDL接口,接下来要再服务端实现这个AIDL接口,先创建一个BookManagerService,代码如下:
package com.qian.aidlipc;import java.util.List;import java.util.concurrent.CopyOnWriteArrayList;import java.util.concurrent.atomic.AtomicBoolean;import android.app.Service;import android.content.Intent;import android.content.pm.PackageManager;import android.os.Binder;import android.os.IBinder;import android.os.Parcel;import android.os.RemoteCallbackList;import android.os.RemoteException;import android.os.SystemClock;import android.util.Log;public class BookManagerService extends Service { private static final String TAG = "BookManagerService"; private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>(); 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的典型实现,首先在onCreate中中石化添加了两本图书的信息,然后创建了一个Binder对象并在onBind方法中返回它,这个对象继承自IBookManager.Stub对象,并实现了它内部的AIDL方法,这个过程在浅谈Binder机制一文中已经详细说明了,这里不多说,也就是前面所说的,将暴露给客户端的接口在Service中实现。其中实现了getBookList,addBook两个方法,实现过程也比较简单,只是为了说明原理,不用搞那么复杂,实际情况中可能会出现很复杂的情况,但是原理都一样。注意这里采用CopyOnWriteArrayList,这个CopyOnWriteArrayList支持并发读写。实际上AIDL方法是在服务端的Binder线程池中执行的,这样就有多有客户端同时访问的情况,所以需要处理线程同步问题,而这个CopyOnWriteArrayList就可以处理线程同步。
然后注册一下远程服务:
<service android:name="com.qian.aidlipc.BookManagerService" android:process=":remote" > </service>
4、客户端的实现
客户端的实现,首先要绑定服务,绑定成功后将服务端返回的Binder对象转换成AIDL接口,然后通过这个接口去调用服务端的远程方法,代码如下:
package com.qian.aidlipc;import java.util.List;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 com.qian.aidlipc.R;public class BookManagerActivity extends Activity { private static final String TAG = "BookManagerActivity"; private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { IBookManager bookManager = IBookManager.Stub.asInterface(service); try { List<Book> list = bookManager.getBookList(); Log.i(TAG, "query book list:" + list.toString()); Book newBook = new Book(3, "夜莺与玫瑰"); bookManager.addBook(newBook); Log.i(TAG, "add book:" + newBook); List<Book> newList = bookManager.getBookList(); Log.i(TAG, "query book list:" + newList.toString()); } catch (RemoteException e) { e.printStackTrace(); } } public void onServiceDisconnected(ComponentName className) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_book_manager); Intent intent = new Intent(this, BookManagerService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); }}代码很简单,其中IBookManager bookManager = IBookManager.Stub.asInterface(service);就是将服务端返回的Binder对象转换成AIDL接口,再通过这个接口调用远程方法。注册xml然后观察一下Log:
先是getBookList。得到两本书 Android和IOS,然后调用addBook添加了一本书夜莺与玫瑰,然后又调用getBookList。和我们预想的结果是一样的,远程调用方法成功了。
最后再说明一下:
当客户端远程调用服务的方法时,被调用的方法运行在服务端的Binder线程池中,同时客户端线程会被挂起,这个时候如果服务端的方法比较耗时,就会出现客户端线程尝试加被阻塞,而如果这个客户端是UI线程的话,就会出现NR,客户端的onServiceConnected和onServiceDisconnected都是运行在UI线程,所以尽量避免UI线程调用远程方法。而服务端的方法本身就运行在Binder线程池里,所以本身可以执行大量耗时操作,所以不必再开线程执行耗时操作。另外服务端也有可能会运行客户端的回调方法,而如果客户端的这个回调方法比较耗时的话,也会造成服务端ANR,所以最好保证服务端回调接口的地方运行在非UI线程。
- Android中的IPC方式——使用AIDL
- Android中的IPC——AIDL方式
- Android中的IPC方式(二)—— AIDL
- Android中的IPC方式AIDL
- 9.Android中的IPC方式——Bundle、文件共享、Messenger、AIDL、Content-Provider
- 初试Android中的IPC机制(2)————使用AIDL
- Android 中的IPC——AIDL&Binder的应用
- Android中的IPC方式——使用Messenger
- IPC机制系列之三 Android中的IPC方式 (AIDL)
- Android 中的 IPC 方式一:使用 Bundle
- android 中的IPC方式
- Android中的IPC方式
- Android中的IPC方式
- Android中的IPC方式
- Android中的IPC方式
- Android中的IPC方式
- Android中的IPC方式
- Android中的IPC方式
- Android 读写文件整理
- 软件架构师的12项修炼--软技能篇
- Contains Duplicate判断数组是否有重复元素
- 在IntelliJ上操作GitHub
- JavaScript 原型对象的继承方法
- Android中的IPC方式——使用AIDL
- PLC从入门到精通(二) 三相异步电动机基本控制环节与基本电路
- 优化openfire服务器,达到单机20万,集群50万
- Linux 查看CPU信息,机器型号,内存等信息
- QSettings介绍【转】
- Android传感器(四):距离传感器
- Android ButterKnife 使用
- java\大数据牛人 -flychao88
- 坑之:Waiting server-side response timeout