基于binder的跨进程通讯之使用AIDL实现Demo
来源:互联网 发布:info域名 编辑:程序博客网 时间:2024/06/10 17:38
写在前面
上一篇我们介绍了binder机制的基本知识,如果还不太了解binder机制,可进行点击查看:让你一看就明白的Binder机制
binder和AIDL的关系
从应用层的角度来说,Binder类是android中的一个类,它实现了IBinder接口,是binder机制在应用层的核心代理,Binder是客户端和服务端进行通讯的“桥梁”。在android开发中,Binder主要用在service中,包括AIDL和Messenger。普通的service不涉及进程间通讯,无法涉及到binder机制的核心。Messenger的底层其实也是AIDL的实现,那么一直说的AIDL到底是什么呢?其实AIDL文件本质上就是为了方便开发者减少代码编写量,由IDE自动编译生成对应的java文件提供给开发者使用。下面我们将一步一步的去实现。
跨进程通讯对于数据实体的要求
android中的基于binder的跨进程通讯要求实体类需要实现Parcelable接口,只有实现了parcelable接口的实体类才能够成功被传递。下面总结AIDL文件中可以被使用的数据类型:
基本数据类型(int、char、long、boolean等)
String和CharSequence
List:只支持ArrayList,并且里面的元素都可以被AIDL支持
Map:只支持HashMap,并且里面的每个元素都可以被AIDL支持
Parcelable:所有实现了Parcelable接口的对象
AIDL:所有的AIDL接口本身也可以在AIDL中进行使用
使用AIDL进行进程间通讯的大概流程
服务端:
服务端首先创建一个service用来监听客户端连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件的声明,最后在service中进行实现
客户端
客户端需要绑定服务端的service,绑定成功之后将服务端返回的binder对象转成AIDL接口所属的类型,接着就可以调用AIDL的方法了。
项目Demo实现
首先我们需要准备好开发android应用的必要的工具:android studio
在Android Studio中新建一个项目,首先创建一个实现parcelable接口的实体类book。代码细节如下:
创建实现Parcelable接口的实体类
package com.example.zwjian.myapplication;import android.os.Parcel;import android.os.Parcelable;/** * Created by zwjian */public class Book implements Parcelable { private int bookId; private String bookName; public Book(int id, String name) { bookId = id; bookName = name; } 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); } @Override public String toString() { return "名字:" + this.bookName + ",ID:" + this.bookId; }}
上面我们定义了一个Book类,实现了Parcelable接口,在该类中包含两个字段bookID和bookName。
创建Book.aidl文件
AIDL文件要求如果需要使用自己定义的Parcelable对象,那么必须要新建一个和他同名字的AIDL文件,并在其中声明他为parcelable类型。所以我们需要新建一个book.aidl文件
我们在android studio中新建一个aidl文件,然后会发现IDE创建了一个和java文件同级的aidl文件夹
接下来我们在新建的Book.aidl文件中加入book的parcelable声明:
// Book.aidlpackage com.example.zwjian.myapplication;// Declare any non-default types here with import statementsparcelable Book;
创建service将要暴露的接口方法
接下来我们要创建一个接口,将service要提供的方法放在该接口文件中:在aidl文件夹下新建IBookManager.aidl文件,代码如下:
// IBookManager.aidlpackage com.example.zwjian.myapplication;// 虽然book.aidl和IBookManager.aidl都在同一包下,但是还需要import进来import com.example.zwjian.myapplication.Book;interface IBookManager {//声明2个方法,这两个方法会在service中进行实现 List<Book> getBookList(); void addBook( in Book book);}
完成上述操作,我们点击“build—-> make project”,build之后,我们就可以得到IDE智能帮我们创建的IBookManager.java文件了。
那么生成的IBookManager.java文件在哪里呢?我们可以在以下路径中找到:build—>generated—>source—>aidl—>debug,然后我们就可以看到包名中的java文件了。其内容如下:
/* * This file is auto-generated. DO NOT MODIFY. * Original file: /Users/zwjian/AndroidStudioProjects/MyApplication/aidlTest/src/main/aidl/com/example/zwjian/myapplication/IBookManager.aidl */package com.example.zwjian.myapplication;public interface IBookManager extends android.os.IInterface { /** * Local-side IPC implementation stub class. * stub是一个BInder类,当客户端和服务器端都在同一进程,方法调用不会走跨进程的transact过程。 * 反之,需要走transact过程,这个逻辑由Stub.Proxy来实现 */ public static abstract class Stub extends android.os.Binder implements com.example.zwjian.myapplication.IBookManager { // Binder的唯一标示,一般用当前的binder类名表示 private static final java.lang.String DESCRIPTOR = "com.example.zwjian.myapplication.IBookManager"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** *用于将服务器端的Binder对象转换成客户端所需要的AIDL接口类型对象,这种操作区分进程:统一进程时,此方法返回服务端的stub对象本身。 反之返回的是stub.proxy对象 */ public static com.example.zwjian.myapplication.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.example.zwjian.myapplication.IBookManager))) { return ((com.example.zwjian.myapplication.IBookManager) iin); } return new com.example.zwjian.myapplication.IBookManager.Stub.Proxy(obj); } //返回当前binder对象 @Override public android.os.IBinder asBinder() { return this; } //该方法运行在服务器端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交给该方法执行。 //服务器端通过code可以确定客户端要请求的方法是哪个,接着从data中取出请求参数(如果有的话),然后去执行目标方法。 //执行完毕之后将结果放入reply参数中进行返回 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_getBookList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.example.zwjian.myapplication.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); com.example.zwjian.myapplication.Book _arg0; if ((0 != data.readInt())) { _arg0 = com.example.zwjian.myapplication.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.zwjian.myapplication.IBookManager { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } //该方法和下面的addBook方法一样,都运行在客户端,客户端调用该方法的流程如下: //首先创建该方法需要的输入型参数_data,输出Parcel型参数_reply和返回值list,然后如果有输入参数则将数据放进_data中, //接着调用transact方法发起远程过程调用(RPC)请求,同时线程挂起,然后服务器端的onTransact方法会执行,直到RPC过程返回。 //当前线程继续执行,并从_reply中取出RPC过程的返回值 @Override public java.util.List<com.example.zwjian.myapplication.Book> getBookList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.example.zwjian.myapplication.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.example.zwjian.myapplication.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addBook(com.example.zwjian.myapplication.Book book) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); if ((book != null)) { _data.writeInt(1); book.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } //这两个静态变量ID标识在transact过程中客户端请求的到底是哪个方法 static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public java.util.List<com.example.zwjian.myapplication.Book> getBookList() throws android.os.RemoteException; public void addBook(com.example.zwjian.myapplication.Book book) throws android.os.RemoteException;}
以上我们基本上将AIDL文件生成对应java文件的过程讲述完毕,并且做了比较详细的函数说明,下面开始实现自定义的service类
创建service类
上部分我们定义了aidl接口,我们接下来需要在service中实现这个接口。我们在Android Studio中创建一个BookManagerService类:
package com.example.zwjian.myapplication;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.os.RemoteException;import java.util.List;import java.util.concurrent.CopyOnWriteArrayList;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; }}
上面的代码比较简单,核心就在于onBinder方法返回的mBinder对象了,我们可以发现mBinder代表的是IBookManager类中的Stub这个binder类,并且在service中进行了方法实现。
值得注意的一点是,由于是在同一个应用中的项目Demo,为了突出跨进程通讯,我们需要给该service设置另外一个进程执行(android:process属性):
<service android:name=".BookManagerService" android:enabled="true" android:exported="true" android:process=":myService"> </service>
实现client端代码
client端其实也就是指的是各种activity中的代码实现了。主要流程:首先绑定远程服务,绑定成功之后将服务端返回的Binder对象转化成为AIDL接口,然后通过这个接口去调用服务端的远程方法就好。代码如下:
package com.example.zwjian.myapplication;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import java.util.List;public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //通过binder得到IBookManager的引用 IBookManager iBookManager = IBookManager.Stub.asInterface(service); try { List<Book> list = iBookManager.getBookList(); for (Book book : list) { Log.d(TAG, "bookInfo:" + book.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); //开始绑定service Intent intent = new Intent(this, BookManagerService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); }}
同样,代码实现很简单,我们主要是注意要在onDestory中不要忘记解绑service。
以上,我们的demo就大功告成了,可以去运行下,运行结果如下:
- 基于binder的跨进程通讯之使用AIDL实现Demo
- android使用AIDL实现跨进程通讯(IPC)
- android使用AIDL实现跨进程通讯(IPC)
- 示例:Android使用AIDL实现跨进程通讯(IPC)
- Android开发中实现跨进程通讯的AIDL接口
- Android开发中实现跨进程通讯的AIDL接口
- Android开发中实现跨进程通讯的AIDL接口
- Android之AIDL跨进程通讯
- android 利用AIDL实现Binder跨进程通信
- Android AIDL跨进程通讯
- android AIDL,跨进程通讯
- 使用AIDL实现Android的跨进程通信
- 使用AIDL实现跨进程Service的绑定
- AIDL-AndRoid接口描述语言实现跨进程通讯
- Android使用Aidl实现跨进程通信
- android 跨进程通讯(主要AIDL)的学习心得
- Messenger——比AIDL简单的跨进程通讯
- Android跨进程通信-AIDL的使用
- (转)javascript异步编程的四种方法
- jQuery中的end()
- 并发编程中的几个名词概念
- TensorFlow 神经网络优化
- 网络连接的net命令
- 基于binder的跨进程通讯之使用AIDL实现Demo
- android中的Button按钮居中(水平垂直中)
- Educational Codeforces Round 21 C. Tea Party
- (转)前端面试题
- 百度ueditor上传系列问题
- apue第八章 进程控制(3) exec函数族
- Hive学习之抽样(Sampling)
- elasticsearch FunctionScore Java API
- bzoj2442