美文网首页
android studio下AIDL 使用

android studio下AIDL 使用

作者: 有点健忘 | 来源:发表于2019-02-18 15:04 被阅读23次

    参考
    https://www.cnblogs.com/chase1/p/7135961.html
    https://developer.android.com/guide/components/aidl

    1. 服务端添加aidl文件
      如下图所示,在src目录上,右键new一个aidl文件,写上aidl文件的名字,就自动生成了
    image.png

    结构如下


    image.png

    生成的aidl文件如下,接口里的方法改成自己实际需要的即可

    package com.charliesong.demo0327;
    
    // Declare any non-default types here with import statements
    
    interface IMyAidlInterface {
         String getPid();
         void changeState(int state);
         int getState();
    }
    

    然后在下图所示的地方可以看到自动生成的同名java文件,如果没有生成,或者你修改了aidl接口文件的方法,那么点下build》make project也可以生成对应的java文件的。


    image.png
    1. 写个service
      主要就是实例化一个binder,也就是我们上边定义的aidl接口的对象,如下,然后onBind方法里返回即可。
    class ServiceNothing:Service(){
        override fun onBind(intent: Intent?): IBinder? {
            println("ServiceNothing on bind================")
            return binder
        }
    
        var stateOld=-1
        private val binder=object :IMyAidlInterface.Stub(){
            override fun getPid(): String {
    
                return packageName
            }
    
            override fun changeState(state: Int) {
                stateOld=state
            }
    
            override fun getState(): Int {
              return  stateOld
            }
        }
    }
    
    1. 注册服务
      intent-filter 是用来在别的app启动这个服务用的
            <service android:name=".a1.ServiceNothing" >
                <intent-filter>
                 <action android:name="com.xx.xxx"/>
                  </intent-filter>
            </service>
    
    1. 复制服务端的aidl目录的文件到客户端
      就是main目录下那个aidl目录,复制到需要的工程main目录下,然后make project 。
      使用就比较简单了,如下bind服务
            Intent intent=new Intent("com.xx.xxx");
            intent.setPackage("com.charliesong.demo0327");
            bindService(intent,conn,Context.BIND_AUTO_CREATE);
    

    conn如下

     IMyAidlInterface aidlInterface;
        private ServiceConnection conn=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
    
                aidlInterface=IMyAidlInterface.Stub.asInterface(service);
              //拿到aidlInterface 就可以调用它里边的方法拉。
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                aidlInterface=null;
            }
        };
    

    上边简单的就完事了。

    自定义类

    image.png

    首先我们可以看到用android studio 右键生成的aidl目录和我们的java目录不在一起的,在这个aidl目录下,添加aidl文件是没啥问题的,系统会自动识别的,如果添加java类,系统是不识别的。
    所以我们自定义类有两种办法:
    一种,你把要自定义的类写在java目录下,
    另一种,就写在aidl目录下,不过需要在build.gradle文件下添加如下代码

    android {
        compileSdkVersion 27
        defaultConfig {
            applicationId "com.charliesong.demo0327"
            minSdkVersion 18
    //省略
        }
    
    //需要添加下边的代码,主要是把aidl目录添加到java目录下
        sourceSets {
            main {
                java.srcDirs = ['src/main/java', 'src/main/aidl']
            }
        }
    

    我们这里采专用第二种

    1. 首先自定义一个类,实现Parcelable接口
    public class OurPacket2 implements Parcelable 
    

    然后添加同名的aidl文件,只需要两行代码,一个是package,一个parcelable 后边跟着类的名字

    // OurPacket2.aidl
    package com.charliesong.demo0327;
    
    // Declare any non-default types here with import statements
    parcelable OurPacket2;
    
    1. 之后aidl文件里就可以用这个自定义的类了,如下
      注意:import必须添加,方法的参数前边必须添加 in ,out 或者inout
      关于这3种tag的介绍可以看这里https://blog.csdn.net/luoyanglizi/article/details/51958091
    package com.charliesong.demo0327;
    import com.charliesong.demo0327.OurPacket2;
    interface IMyAidlInterface {
         String getPid();
         void setaa(inout OurPacket2 packet);
    }
    

    完事编译,完事挂了。一直提示自定义类找不到readFromParcel方法,那就给他加一个呗。完事就ok了

    public class OurPacket2 implements Parcelable {
    
        public void readFromParcel(Parcel in){
            pid=in.readInt();
            name=in.readString();
        }
    
    1. 其他步骤就和普通的一样了。把adil目录复制过去即可,记得客户端也添加这个,这样方便,aidl相关的 都在一个目录下。
        sourceSets {
            main {
                java.srcDirs = ['src/main/java', 'src/main/aidl']
            }
        }
    

    自定义数据数据流向in,out,inout

    上边有链接,有详细的介绍,可以去看看,下边只说结论
    如下,增加3个方法测试

         void addPacketIn(in OurPacket2 packet);
         void addPacketOut(out OurPacket2 packet);
         void addPacketInOut(inout OurPacket2 packet);
    

    然后服务端的实现如下,就是打印下接收点到的值,并且修改name值

        private val binder=object :IMyAidlInterface.Stub(){
            override fun addPacketIn(packet: OurPacket2) {
                println("addPacket in....${packet}")
                packet.name="in"
            }
    
            override fun addPacketOut(packet: OurPacket2) {
                println("addPacket out....${packet}")
                packet.name="out"
            }
    
            override fun addPacketInOut(packet: OurPacket2) {
                println("addPacket inout....${packet}")
                packet.name="in out"
            }
    

    客户端也一样,打印,里边有打印的日志

            public void onServiceConnected(ComponentName name, IBinder service) {
    
                aidlInterface=IMyAidlInterface.Stub.asInterface(service);
                try {
    
                OurPacket2 packet2=new OurPacket2(111,"aaaa");
                aidlInterface.addPacketIn(packet2);
                System.out.println("client1=========="+packet2);
    
                OurPacket2 packet22=new OurPacket2(111,"aaaa");
                aidlInterface.addPacketOut(packet22);
                System.out.println("client2=========="+packet22);
    
                OurPacket2 packet222=new OurPacket2(111,"aaaa");
                aidlInterface.addPacketInOut(packet222);
                System.out.println("client3=========="+packet222);
    
                    //addPacket in....packet===pid:111 name:aaaa
                    //addPacket out....packet===pid:0 name:null
                    //addPacket inout....packet===pid:111 name:aaaa
    
                    //client1==========packet===pid:111 name:aaaa
                    //client2==========packet===pid:0 name:out
                    //client3==========packet===pid:111 name:in out
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    

    in:表示数据只能从客户端到服务端,单向的,log可以看到服务端修改是无用的,name还是aaaa
    out:表示数据只能从服务端传给客户端,也是单向的,log可以看到,我们通过客户端传了个有数据的packet给服务端,可服务端打印的pid==0,name是null,说明数据传不过去,相反,在服务端修改了name为out之后,客户端打印的packet的name也成了out了
    inout:就是双向的,客户端可以传数据给服务端,服务端修改以后,客户端也被修改了。
    简单看下自动生成的同名接口java文件
    只看下in,和out,至于inout就是两者一起了。
    看方法也能看到in的话,使用了参数packet
    out的话没有使用参数packet,不过在方法结尾,把参数packet同步了下最后的数据

                public void addPacketIn(com.charliesong.demo0327.OurPacket2 packet) 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 ((packet != null)) {
                            _data.writeInt(1);
                            packet.writeToParcel(_data, 0);//可以看到数据packet被写到data里了
                        } else {
                            _data.writeInt(0);
                        }
                        mRemote.transact(Stub.TRANSACTION_addPacketIn, _data, _reply, 0);
                        _reply.readException();
    //packet没有被修改
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    
    //对于out,packet参数根本就没被使用,只在最后复制了下reply数据,
                public void addPacketOut(com.charliesong.demo0327.OurPacket2 packet) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        mRemote.transact(Stub.TRANSACTION_addPacketOut, _data, _reply, 0);
                        _reply.readException();
                        if ((0 != _reply.readInt())) {
                            packet.readFromParcel(_reply);
                        }
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    

    暂时到这里

    用的不多,都忘了,复习下,以后需要再看,如有错误,会及时修改的。

    相关文章

      网友评论

          本文标题:android studio下AIDL 使用

          本文链接:https://www.haomeiwen.com/subject/jptmeqtx.html