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
AIDL_第1张图片

源码地址

https://github.com/jackwolf1/aidl

更多相关文章

  1. Android Studio安装app 报错的问题It is possible that this iss
  2. Google Maps API Key申请方法及地址
  3. android 笔记 --- Android Bitmap 建立或取得的方法
  4. Android自带Music播放器更新播放时间和进度条的方法
  5. android使用ant编译找不到apkbuilder.jar的错误的解决方法
  6. Android studio 连接数据库小经历遇到的问题以及解决方法(java.sq
  7. android 永远锁屏解决方法

随机推荐

  1. mysql left join快速转inner join的过程
  2. MySQL 十大常用字符串函数详解
  3. Mysql中调试存储过程最简单的方法
  4. mysql如何配置白名单访问
  5. Mysql数据库按时间点恢复实战记录
  6. 浅析MySQL如何实现事务隔离
  7. MySQL开启事务的方式
  8. MySQL中IF()、IFNULL()、NULLIF()、ISNUL
  9. 解决mysql问题:由于找不到MSVCR120.dll,
  10. 解决mysql:ERROR 1045 (28000): Access de