AIDL
16lz
2021-01-23
AIDL
- 客户端
- 服务端
- 总结
- 源码地址
AIDL:Android Interface Definition Language,即Android接口定义语言。
服务端:
class MyService : Service() { private val mList: MutableList<People> = mutableListOf() override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { return START_STICKY } override fun onBind(intent: Intent?): IBinder? { return mBinder } private val mBinder = object : IMyAidlInterface.Stub() { override fun getList(): MutableList<People> { return mList } override fun add(people: People?) { people?.apply { mList.add(this) } } }}
/** * Constant to return from {@link #onStartCommand}: if this service's * process is killed while it is started (after returning from * {@link #onStartCommand}), then leave it in the started state but * don't retain this delivered intent. Later the system will try to * re-create the service. Because it is in the started state, it will * guarantee to call {@link #onStartCommand} after creating the new * service instance; if there are not any pending start commands to be * delivered to the service, it will be called with a null intent * object, so you must take care to check for this. * * This mode makes sense for things that will be explicitly started * and stopped to run for arbitrary periods of time, such as a service * performing background music playback. */
public static final int START_STICKY = 1;
被杀后自动重启,保持启动状态,不保持Intent,重新调用onStartCommand,无新Intent则为空Intent—杀死重启后,不继续执行先前任务,能接受新任务。
IMyAidlInterface 就是自己定义得AIDL
package com.example.myservice;import com.example.myservice.IPeople;interface IMyAidlInterface { void add(in People people); List<People> getList();}
这里使用了自定义类People
package com.example.myservice;parcelable People;
这里必须使用parcelable
下面是People代码
package com.example.myserviceimport android.os.Parcelimport android.os.Parcelabledata class People( var name: String? = "", var id: Int = 1) : Parcelable { constructor(source: Parcel) : this( source.readString(), source.readInt() ) override fun describeContents() = 0 override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) { writeString(name) writeInt(id) } companion object { @JvmField val CREATOR: Parcelable.Creator<People> = object : Parcelable.Creator<People> { override fun createFromParcel(source: Parcel): People = People(source) override fun newArray(size: Int): Array<People?> = arrayOfNulls(size) } }}
服务端代码就搞定了。
下面是客户端代码:
package com.example.myservice;import com.example.myservice.IPeople;interface IMyAidlInterface { void add(in People people); List<People> getList();}
必须和刚才服务端写得AIDL完全一样。注意包名
class MainActivity : AppCompatActivity() { var mAidl: IMyAidlInterface? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) bind() btn.setOnClickListener { mAidl?.add(People("名字", (0..10).random())) tv.text = mAidl?.list.toString() } } private fun bind() { val intent = Intent() intent.component = ComponentName("com.example.myservice", "com.example.myservice.MyService") bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE) } private val mServiceConnection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { mAidl = IMyAidlInterface.Stub.asInterface(service) } override fun onServiceDisconnected(name: ComponentName?) { mAidl = null } } override fun onDestroy() { super.onDestroy() unbindService(mServiceConnection) }}
客户端绑定服务代码。
客户端
获取aidl对象的方法
IMyAidlInterface.Stub.asInterface(service)
/** * Cast an IBinder object into an com.example.myservice.IMyAidlInterface interface, * generating a proxy if needed. */ public static com.example.myservice.IMyAidlInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.myservice.IMyAidlInterface))) { return ((com.example.myservice.IMyAidlInterface)iin); } return new com.example.myservice.IMyAidlInterface.Stub.Proxy(obj); }
/** * Use information supplied to attachInterface() to return the * associated IInterface if it matches the requested * descriptor. */ public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) { if (mDescriptor != null && mDescriptor.equals(descriptor)) { return mOwner; } return null; }
可以看出,如果本当前进程有直接返回当前进程得,如果没有,新建一个代理 Stub.Proxy
private static class Proxy implements com.example.myservice.IMyAidlInterface { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } }
这里是Proxy得实现。
@Override public void add(com.example.myservice.People people) 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 ((people!=null)) { _data.writeInt(1); people.writeToParcel(_data, 0); } else { _data.writeInt(0); } //发送数据 boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().add(people); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } }
对应自定义个add方法。
/** * Default implementation rewinds the parcels and calls onTransact. On * the remote side, transact calls into the binder to do the IPC. */ public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException { if (false) Log.v("Binder", "Transact: " + code + " to " + this); if (data != null) { //设置数据,调用native层 data.setDataPosition(0); } boolean r = onTransact(code, data, reply, flags); if (reply != null) { reply.setDataPosition(0); } return r; }
这里是Binder传输数据的代码,里面调用了onTransact方法
服务端
object : IMyAidlInterface.Stub()
服务端获取IBinder
public static abstract class Stub extends android.os.Binder implements com.example.myservice.IMyAidlInterface
需要重写得两个方法
public void add(com.example.myservice.People people) throws android.os.RemoteException;public java.util.List<com.example.myservice.People> getList() throws android.os.RemoteException;
通过这个onTransact方法调用
case TRANSACTION_add: { data.enforceInterface(descriptor); com.example.myservice.People _arg0; if ((0!=data.readInt())) { _arg0 = com.example.myservice.People.CREATOR.createFromParcel(data); } else { _arg0 = null; } //调用add方法 this.add(_arg0); reply.writeNoException(); return true; }
这里面的add,就相当于客户端调用add方法后,把值传递过来。
总结
客户端是 Proxy 使用transact
中间是 Binder
服务端是 Stub 使用onTransact
源码地址
https://github.com/jackwolf1/aidl
更多相关文章
- Android Studio安装app 报错的问题It is possible that this iss
- Google Maps API Key申请方法及地址
- android 笔记 --- Android Bitmap 建立或取得的方法
- Android自带Music播放器更新播放时间和进度条的方法
- android使用ant编译找不到apkbuilder.jar的错误的解决方法
- Android studio 连接数据库小经历遇到的问题以及解决方法(java.sq
- android 永远锁屏解决方法