Binder是Android中的一个类,它实现了一个IBinder接口,是Android中跨进程的通信方式,是ServiceManager链接各种Manager(ActivityManager,WindowManager),从Android应用层来说,Binder是客户端和服务端进行通信的桥梁。我们从AIDL来分析Binder工作机制。
创建步骤如下:
一.创建AIDL工程创建IMyAidl.aidl和Person.aidl类
// IMyAidl.aidl package com.example.cmj.ipc; import com.example.cmj.ipc.bean.Person; interface IMyAidl { void addPerson(in Person person); List<Person> getPersonList(); }
// Person.aidl package com.example.cmj.ipc.bean; parcelable Person;
二.创建Person.java类 package com.example.cmj.ipc.bean; import android.os.Parcel; import android.os.Parcelable; public class Person implements Parcelable { private String mName; public Person(String name) { mName = name; } protected Person(Parcel in) { mName = in.readString(); } public static final Creator<Person> CREATOR = new Creator<Person>() { @Override public Person createFromParcel(Parcel in) { return new Person(in); } @Override public Person[] newArray(int size) { return new Person[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mName); } @Override public String toString() { return "Person{" + "mName='" + mName + '\'' + '}'; } }
三.make project生成IMyAidl.java文件
package com.example.cmj.ipc; // Declare any non-default types here with import statements public interface IMyAidl extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.cmj.ipc.IMyAidl { private static final java.lang.String DESCRIPTOR = "com.example.cmj.ipc.IMyAidl"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.cmj.ipc.IMyAidl interface, * generating a proxy if needed. */ public static com.example.cmj.ipc.IMyAidl asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.cmj.ipc.IMyAidl))) { return ((com.example.cmj.ipc.IMyAidl)iin); } return new com.example.cmj.ipc.IMyAidl.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @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_addPerson: { data.enforceInterface(DESCRIPTOR); com.example.cmj.ipc.bean.Person _arg0; if ((0!=data.readInt())) { _arg0 = com.example.cmj.ipc.bean.Person.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addPerson(_arg0); reply.writeNoException(); return true; } case TRANSACTION_getPersonList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.example.cmj.ipc.bean.Person> _result = this.getPersonList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.cmj.ipc.IMyAidl { 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; } @Override public void addPerson(com.example.cmj.ipc.bean.Person person) 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 ((person!=null)) { _data.writeInt(1); person.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public java.util.List<com.example.cmj.ipc.bean.Person> getPersonList() 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.cmj.ipc.bean.Person> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.example.cmj.ipc.bean.Person.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public void addPerson(com.example.cmj.ipc.bean.Person person) throws android.os.RemoteException; public java.util.List<com.example.cmj.ipc.bean.Person> getPersonList() throws android.os.RemoteException; }
四.生成客户端MyServiceActivity.java
public class MyServiceActivity extends AppCompatActivity { private Button mBtn; private List<Person> mPersonList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_service); mBtn = findViewById(R.id.btn); mBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent1 = new Intent(getApplicationContext(), MyAidlService.class); bindService(intent1, mConnection, BIND_AUTO_CREATE); //addPerson(); } }); } private void addPerson() { Random random = new Random(); Person person = new Person("shixin" + random.nextInt(10)); try { mIMyAidl.addPerson(person); mPersonList = mIMyAidl.getPersonList(); } catch (RemoteException e) { e.printStackTrace(); } } private IMyAidl mIMyAidl; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //连接后拿到 Binder,转换成 AIDL,在不同进程会返回个代理 mIMyAidl = IMyAidl.Stub.asInterface(service); try { List<Person> personList = mIMyAidl.getPersonList(); Log.d("aidl",personList.toString()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mIMyAidl = null; } }; }
五.生成服务端 public class MyAidlService extends Service { private ArrayList<Person> mPersons = new ArrayList<>(); @Override public void onCreate() { super.onCreate(); mPersons.add(new Person("cmj")); } /** * 创建生成本地Binder对象 */ private IBinder mIBinder = new IMyAidl.Stub() { @Override public void addPerson(Person person) throws RemoteException { mPersons.add(person); } @Override public List<Person> getPersonList() throws RemoteException { return mPersons; } }; /** * 客户端与服务端绑定时的回调,返回 mIBinder 后客户端就可以通过它远程调用服务端的方法,即实现了通讯 * * @param intent * @return */ @Nullable @Override public IBinder onBind(Intent intent) { return mIBinder; } }
我们进一步分析IMyAidl.java文件
1.DESCRIPTION: Binder的唯一标识,例如:com.example.cmj.ipc.IMyAidl 2.asInterface(android.os.IBinder obj) 用于获取服务端Binder对象转换成客户端所需的AIDL接口类型的对象,这种转换过程是区分进程的,如果客户端和服务端在同一个进程,那么返回服务端Stub对象本身,否则是Stub.Proxy对象。 3.asBinder 返回当前Binder对象 4.onTransact 此方法运行在服务端,当客户端发起请求会通过系统底层封装后交由此方法来处理,服务端通过code可以确定客户端请求的方法,接着从data取出数据,执行完毕就向reply写入返回值。 5.Proxy.getBookList 输入类型Parcel对象_data,输出类型Parcel对象_reply和返回值对象List;然后把信息写入_data,接着调用transact方法发起RPC请求,服务端onTransact会被调用,直到RPC返回结果,从_reply取出RPC过程结果,最后返回_reply中的数据。 6.Proxy.addBook 没有返回值不需要从_reply取出返回值