AIDL基本用法

来源:互联网 发布:java转smail工具 编辑:程序博客网 时间:2024/06/11 14:18

前言

Aidl是android进程通信的一个办法,通过aidl我们可以跨进程调用方法。如果你仔细看完这篇文章,你将会有以下收获:

1、aidl的基本使用2、aidl传递自定义对象3、client实现对Server的监听

使用Aidl步骤


1、在Server端创建一个aidl文件,把服务端想对外提供的服务在这个文件中声明。声明之后对AS进行rebuild,然后系统会为我们自动生成一个java文件

2、在Server端创建一个Service,Service的目的是为了监听client的连接请求,当有连接请求到来的时候,我们把生成java文件的stub返回

3、client绑定远程Service,并把Server端返回的Binder对象转换成AIDL接口的所属类型。

1、 声明Aidl文件

IMyAidl.aidl(这个aidl文件是对外提供服务的)

// IMyAidl.aidlpackage com.example.xiaojun.learningdemo_jun;import com.example.xiaojun.learningdemo_jun.Person;import com.example.xiaojun.learningdemo_jun.NotificationListener;interface IMyAidl {     int addNumbers(int a,int b);     Person getPerson();     //client可以通过这样设置或者取消对server内容的监听     void setListener(NotificationListener listener);     void removeListener(NotificationListener listener);}

NotificationListener.aidl(server 提供给client的监听接口,当有client感兴趣的内容时,server会通知client)

// NotificationListener.aidlpackage com.example.xiaojun.learningdemo_jun;interface NotificationListener {    void notifyMessage(String msg);}

Person.aidl(主要是为了演示怎么通过aidl传递自定义对象)

// Person.aidlpackage com.example.xiaojun.learningdemo_jun;parcelable Person;

备注:Person是自定义对象,它实现了Parcelable接口。创建Person.aidl是为了演示怎么通过aidl传递自定义对象。
aidl支持数据类型:

1、基本数据类型(int,char,float...)2、String 和 CharSequence3、实现Parcelable的对象4、Aidl接口本身5、ArrayList,或者HashMap对象容纳的上述支持对象

Person.kt

package com.example.xiaojun.learningdemo_junimport android.os.Parcelimport android.os.Parcelable/** * Created by XiaoJun on 2017/9/4. * Version 1.0.0 */class Person() :Parcelable {    var name:String? = null    var age:Int? = null    constructor(parcel: Parcel) : this() {        name = parcel.readString()        age = parcel.readInt()    }    override fun writeToParcel(parcel: Parcel, flags: Int) {        parcel.writeString(name)        parcel.writeInt(age!!)    }    //只有有文件描述符的时候返回1    override fun describeContents(): Int {        return 0    }    companion object CREATOR : Parcelable.Creator<Person> {        override fun createFromParcel(parcel: Parcel): Person {            return Person(parcel)        }        override fun newArray(size: Int): Array<Person?> {            return arrayOfNulls(size)        }    }    override fun toString(): String {        return "Person(name=$name, age=$age)"    }}

IDE自动生成的java文件

我们每创建一个aidl文件,IDE都会自动生成一个Java文件。事实上,我们通过aidl进行跨进程通信不是依赖aidl文件,而是生成的java文件。我们写aidl文件是为了让IDE帮我们生成对应的Java文件。
IMyAidl.java

package com.example.xiaojun.learningdemo_jun;// Declare any non-default types here with import statementspublic interface IMyAidl extends android.os.IInterface {    /**     * Local-side IPC implementation stub class.     */    public static abstract class Stub extends android.os.Binder implements com.example.xiaojun.learningdemo_jun.IMyAidl {        private static final java.lang.String DESCRIPTOR = "com.example.xiaojun.learningdemo_jun.IMyAidl";        /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.example.xiaojun.learningdemo_jun.IMyAidl interface,         * generating a proxy if needed.         */        public static com.example.xiaojun.learningdemo_jun.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.xiaojun.learningdemo_jun.IMyAidl))) {                return ((com.example.xiaojun.learningdemo_jun.IMyAidl) iin);            }            return new com.example.xiaojun.learningdemo_jun.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_addNumbers: {                    data.enforceInterface(DESCRIPTOR);                    int _arg0;                    _arg0 = data.readInt();                    int _arg1;                    _arg1 = data.readInt();                    int _result = this.addNumbers(_arg0, _arg1);                    reply.writeNoException();                    reply.writeInt(_result);                    return true;                }                case TRANSACTION_getPerson: {                    data.enforceInterface(DESCRIPTOR);                    com.example.xiaojun.learningdemo_jun.Person _result = this.getPerson();                    reply.writeNoException();                    if ((_result != null)) {                        reply.writeInt(1);                        _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);                    } else {                        reply.writeInt(0);                    }                    return true;                }                case TRANSACTION_setListener: {                    data.enforceInterface(DESCRIPTOR);                    com.example.xiaojun.learningdemo_jun.NotificationListener _arg0;                    _arg0 = com.example.xiaojun.learningdemo_jun.NotificationListener.Stub.asInterface(data.readStrongBinder());                    this.setListener(_arg0);                    reply.writeNoException();                    return true;                }                case TRANSACTION_removeListener: {                    data.enforceInterface(DESCRIPTOR);                    com.example.xiaojun.learningdemo_jun.NotificationListener _arg0;                    _arg0 = com.example.xiaojun.learningdemo_jun.NotificationListener.Stub.asInterface(data.readStrongBinder());                    this.removeListener(_arg0);                    reply.writeNoException();                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }        private static class Proxy implements com.example.xiaojun.learningdemo_jun.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 int addNumbers(int a, int b) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                int _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeInt(a);                    _data.writeInt(b);                    mRemote.transact(Stub.TRANSACTION_addNumbers, _data, _reply, 0);                    _reply.readException();                    _result = _reply.readInt();                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }            @Override            public com.example.xiaojun.learningdemo_jun.Person getPerson() throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                com.example.xiaojun.learningdemo_jun.Person _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getPerson, _data, _reply, 0);                    _reply.readException();                    if ((0 != _reply.readInt())) {                        _result = com.example.xiaojun.learningdemo_jun.Person.CREATOR.createFromParcel(_reply);                    } else {                        _result = null;                    }                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }//client可以通过这样设置或者取消对server内容的监听            @Override            public void setListener(com.example.xiaojun.learningdemo_jun.NotificationListener listener) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));                    mRemote.transact(Stub.TRANSACTION_setListener, _data, _reply, 0);                    _reply.readException();                } finally {                    _reply.recycle();                    _data.recycle();                }            }            @Override            public void removeListener(com.example.xiaojun.learningdemo_jun.NotificationListener listener) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));                    mRemote.transact(Stub.TRANSACTION_removeListener, _data, _reply, 0);                    _reply.readException();                } finally {                    _reply.recycle();                    _data.recycle();                }            }        }        static final int TRANSACTION_addNumbers = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);        static final int TRANSACTION_getPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);        static final int TRANSACTION_setListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);        static final int TRANSACTION_removeListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);    }    public int addNumbers(int a, int b) throws android.os.RemoteException;    public com.example.xiaojun.learningdemo_jun.Person getPerson() throws android.os.RemoteException;//client可以通过这样设置或者取消对server内容的监听    public void setListener(com.example.xiaojun.learningdemo_jun.NotificationListener listener) throws android.os.RemoteException;    public void removeListener(com.example.xiaojun.learningdemo_jun.NotificationListener listener) throws android.os.RemoteException;}

IMyAidl.java文件说明:

1、DESCRIPTOR:Binder的唯一标识,一般使用的是当前Binder的类名表示。
2、asInterface(android.os.IBinder obj):将服务端返回的Binder对象转换成客户端所需要的AIDL接口类型对象。
3、asBinder返回当前Binder对象本身
4、onTransact这个方法运行在服务端的Binder线程池中,当客户端发起跨进程请求的时候,远程请求会由系统底层封装后交由此方法处理。服务端通过code可以确定client请求的目标方法是什么。接着从data中取出目标方法所需要的参数。当目标方法执行完之后,就像reply写入返回值。如果onTransact返回false的话,那么客户端会请求失败,我们可以根据这个特性做权限认证。
5、Proxy.addNumbers:这个方法运行在客户端,当客户端远程调用addNumbers方法时,它会进行如下操作:


1)、创建该方法所需要的输入型Parcel对象_data,输出型Parcel对象_reply和返回值对象;
2)、把该方法所需要的参数信息都放入data里面;
3)、调用transact方法来发送远程过程调用请求,并挂起当前线程。
4)、服务端的onTransact方法被调用;
5)、远程过程调用返回后,当前线程继续执行,并从_reply中获取远程的返回结果。


2、 Server端创建Service

AidlService的主要工作是当客户端请求连接的时候返回aidl的stub。在stub里面我们实现了定义的功能接口。除此之外,service开启了一个线程,每隔5s更新一次消息,如果有client设置了监听,那么client能够接收到我们设置的消息。
aidl是跨进程之间的通信,所以我们演示aidl功能的时候要让客户端和服务端运行在不同进程。除此之外,我们使用aidl的客户端和服务端要包名完全相同才可以。
本次演示是通过设置应用多进程的方式演示的。我们在manifest文件里面把AidlService设置为运行在不同于Client的进程即可。如下:

 <!-- 注意:process属性是指定service的运行进程,这样指定之后,service运行的进程就是“xiaojun.test” --> <service      android:name=".demo_aidl.AidlService"      android:process="xiaojun.test" />

AidlService.kt

/** * 定义Aidl服务,在manifest声明service并设置运行进程,详情见manifest */class AidlService : Service() {    val listenerList = RemoteCallbackList<NotificationListener>()    var msg = 0    override fun onCreate() {        super.onCreate()        Log.e("AidlService", "Created!")        //200ms后每隔5000ms发送一次更新信息        val scheduledThreadPool = Executors.newScheduledThreadPool(1)        scheduledThreadPool.scheduleAtFixedRate(object : Runnable {            override fun run() {                val N = listenerList.beginBroadcast();                for (i in 0 until N) {                    val li = listenerList.getBroadcastItem(i)                    if (li != null) {                        try {                            li.notifyMessage(msg.toString())                            msg++                        } catch (e: RemoteException) {                            Log.e("AidlService", "Exception: " + e.toString())                        }                    }                    listenerList.finishBroadcast()                }            }        }, 200, 5000, TimeUnit.MILLISECONDS)    }    override fun onBind(p0: Intent?): IBinder {        return object : IMyAidl.Stub() {            override fun addNumbers(a: Int, b: Int): Int {                return a + b            }            override fun getPerson(): Person {                val person = Person()                person.age = 22                person.name = "XiaoJun"                return person            }            override fun setListener(listener: NotificationListener?) {                listenerList.register(listener)            }            override fun removeListener(listener: NotificationListener?) {                listenerList.unregister(listener)            }        }    }}

3、客户端连接服务

下面代码很多,不过主要是做了以下几个工作:
1、连接服务端并把服务端返回的binder转换成aidl接口
2、设置服务端的通知监听,并Toast通知的内容
3、点击getPerson进行getPerson的远程调用
3、点击addNumber进程addNumber的远程调用
ClientAidlActivity.kt

class ClientAidlActivity : AppCompatActivity(), View.OnClickListener {    private var myAdil:IMyAidl? = null    private var conn:MServiceConnection? = null    private var handler:Handler? = null    private var listener : MListener? = null    private val NOTIFICATION_COMES = 1    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_aidl)        init()    }    fun init() {        val intent = Intent(this,AidlService::class.java)        conn = MServiceConnection()        bindService(intent,conn, Context.BIND_AUTO_CREATE)        handler = @SuppressLint("HandlerLeak")        object : Handler() {            override fun handleMessage(msg: Message?) {                if (msg != null && msg.what == NOTIFICATION_COMES){                    Toast.makeText(this@ClientAidlActivity,"SeverNotification "+msg.obj.toString(),Toast.LENGTH_SHORT).show()                }                super.handleMessage(msg)            }        }        getPerson.setOnClickListener(this)        addNumber.setOnClickListener(this)    }    @SuppressLint("SetTextI18n")    override fun onClick(p0: View?) {        p0 ?: return        if (myAdil == null){            Toast.makeText(this,"not connected!",Toast.LENGTH_SHORT).show()            return        }        when (p0.id) {            R.id.getPerson -> {                showArea.text = myAdil?.person.toString()            }            R.id.addNumber -> {                showArea.text = "4 + 3 = \n "+ myAdil?.addNumbers(4,3).toString()            }            else -> {                return            }        }    }    //取消监听,并断开连接    override fun onDestroy() {        super.onDestroy()        myAdil?.removeListener(listener)        unbindService(conn)    }    inner class MServiceConnection : ServiceConnection {        override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {            myAdil = IMyAidl.Stub.asInterface(p1)            listener = MListener()            myAdil?.setListener(listener)            Toast.makeText(this@ClientAidlActivity,"connected!",Toast.LENGTH_SHORT).show()        }        override fun onServiceDisconnected(p0: ComponentName?) {        }    }    inner class MListener : NotificationListener.Stub() {        // 这个函数是工作在binder线程池的,我们需要一个handler将它切换到UI线程        override fun notifyMessage(msg: String?) {            handler?.obtainMessage(NOTIFICATION_COMES,msg)?.sendToTarget()        }    }}

效果图


源码链接:https://github.com/KingLanding94/LearningDemo_Jun

参考:

Android开发艺术探索

1 0
原创粉丝点击