美文网首页我爱编程
Android Studio使用AIDL-实现进程间通讯

Android Studio使用AIDL-实现进程间通讯

作者: ZHDelete | 来源:发表于2018-05-28 19:38 被阅读93次

    参考:

    Android Studio创建AIDL文件并实现进程间通讯实例
    如何在AndroidStudio中使用AIDL
    Android Studio创建AIDL文件并实现进程间通讯实例


    在Android系统中,跨进程通信是非常普遍的事情,它用到了Binder机制处理进程之间的交互。Binder机制会开放
    一些接口给Java层,供android开发工程师调用进程之间通信。这些接口android封装到了AIDL文件里,当我们项目
    用到跨进程通信时可以创建.aidl文件,.aidl文件可以协助我们达到跨进程的通信。
    下面简单介绍用AndroidStudio创建AIDL文件的过程。

    a.新建AIDL文件

    1.项目文件夹 --> new --> 选择AIDL,与 java 同级,都在main文件夹下

    new-aidl.png
    1. 自定义一个接口
    定义接口.png
    1. 3.创建之后我们看到了xxx.aidl文件,然后编辑自己项目需要实现的方法,这里很简单就获取一个字符串的方法String provideName();
    AIDL_接口内容.png

    4.写好之后,我们需要重新ReBuild,完后在项目build/generated/source/aidl/debug/包名 目录下就看到了系统为我们生成的以刚才.aidl文件名命名的java文件。

    build后生成.png

    该java文件系统会自动生成代码:
    Stub:描述了一个Java服务,对应是一个远程的Service。
    Proxy:描述了一个Java服务的代理对象,在Client端就会得到这个对象。
    这两者都实现了IPersonManager接口。
    asInterface:将Java服务的代理对象即一个BinderProxy封装成了一个IPersonManager.Stub.Proxy对象,实现了IPersonManager接口。
    onTransact:负责接收分发进程间的通信。它首先会收到Client发来的请求,不同的方法进入相应的case代码中,然后交给Stub的子类去处理事件,例如 java.lang.String _result = this.getAllName(); 这里的this就可以让它的子类去接收该请求并处理。
    IBinder的transact方法:用来发送进程间的请求。

    b.利用AIDL实现进程间的通讯

    b.1: 接口中只含有基础数据类型:

    如上aidl文件,IPersonManager中只用到了基本数据类型,此时要完善Server端的小项目,还需要新建一个Service。
    Server端代码如下

    public class TrasformerService extends Service {
        private static String names = "alice & iland";
    
        public TrasformerBinder mTransformerBinder;
        @Override
        public void onCreate() {
            super.onCreate();
            mTransformerBinder = new TrasformerBinder();
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return mTransformerBinder ;
        }
    
    
        public class TrasformerBinder extends ITransformerAidlInterface.Stub {
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
    
            }
    
            @Override
            public String provideName() throws RemoteException {
                return names;
            }
        }
    }
    

    继承系统的Service,并建立一个内部类继承IPersonManager.Stub,这里很简单,当客户端请求要获取名字时我们这里把names给到客户端。

    还要在Service端的AndroidMenifest 来注册Service

            <!-- android:process=":remote"//加上这句的话客户端调用会创建一个新的进程-->
            <!--android:exported="true"//默认就为true,可去掉,声明是否可以远程调用-->
            <service
                android:name=".TrasformerService"
                android:exported="true"
                android:process=":remote">
                <intent-filter>
                    <action android:name="com.zhdelete.targetproj.aidl.AIDL_SERVICE" />
                </intent-filter>
            </service>
    

    Client端代码如下(即: 需要数据的一方):

    1.我们需要把Server端的aidl文件复制到Client端,在Client中存放aidl的文件夹也需要跟Server端包名一致。

    • service端的包名如下:


      service_端包名.png

    上图为aidl文件在Server端存放的路径,下图为复制到Client端aidl文件的路径,这里要保持一致,因此Client端需要针对Server端的包名新建一个Package。

    client_端包名.png

    2.client 端的 代码如下:

    class AidlActivity : AppCompatActivity(), View.OnClickListener {
    
    
        lateinit var getBtn: Button
        lateinit var showTv: TextView
    
        var mTransformerAIterface: ITransformerAidlInterface? = null
    
        val TAG = "Client"
        val sc = object : ServiceConnection {
            override fun onServiceDisconnected(name: ComponentName?) {
                Log.d(TAG, "onServiceDisconnected")
                mTransformerAIterface = null
            }
    
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                Log.d(TAG, "onServiceConnected")
                mTransformerAIterface = ITransformerAidlInterface.Stub.asInterface(service)
            }
    
        }
    
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_aidl_get)
            getBtn = findViewById(R.id.get_btn)
            showTv = findViewById(R.id.show_tv)
    
            getBtn.setOnClickListener(this@AidlActivity)
    
            Intent("com.zhdelete.targetproj.aidl.AIDL_SERVICE")
                    .run {
                        setPackage("com.zhdelete.targetproj")
                        bindService(this, sc, Service.BIND_AUTO_CREATE)
                    }
        }
    
    
        override fun onClick(v: View) {
            when (v.id) {
                R.id.get_btn -> {
                    var nameFromServer: String? = null
                    mTransformerAIterface?.let {
                        nameFromServer = it.provideName()
                        showTv.text = nameFromServer
    
                    } ?: let {
                        Log.d(TAG, "mTransormerAIterface null")
                    }
                }
                else -> {
    
                }
            }
        }
    
        override fun onDestroy() {
            super.onDestroy()
            unbindService(sc)
    
        }
    }
    

    在onServiceConnected方法中拿到IPersonManager的代理对象,最终获取到 alice & ilan,与服务端数据一致。

    注意:

    • bindService方法在5.0以后做出改变,隐式意图需要设置Package 或者 Commponent,直接定义一个action是报异常的。
    Intent intent = new Intent("com.ly.testaidlserver.aidl.AIDL_SERVICE"); 
    intent.setPackage("com.ly.testaidlserver");
    bindService(intent,sc, Service.BIND_AUTO_CREATE); 
    

    3.当我们启动项目的时候,如果在Activity中IPersonManager找不到报出异常,请在app的build.gradle中添加aidl文件指名目录,如本例中添加,

      sourceSets{
        main {
          aidl.srcDirs = ['src/main/aidl','src/main/java']
        }
      }
    

    b.2接口文件中含有复杂数据类型

    1.新建一个Person.aidl 接口 , 注意,这里必须新建AIDL接口,而不能在原接口上添加方法,否则,报错:

    "xxx\"build-tools\27.0.3\aidl.exe'' finished with non-zero exit value 1
    

    新的Person.aidl 如下

    // Person.aidl
    package com.zhdelete.targetproj;
    
    parcelable Person;
    

    2.新建一个Person实体类,为了能在进程间进行通信必须实现Parcelable接口。

    3.在TrasformerService中添加了一个方法,这里注意用到的Person类必须将包名improt进去。即显示的 写在接口 声明上面:

    // IMyAidlInterface.aidl
    package com.zhdelete.targetproj;
    
    // Declare any non-default types here with import statements
    //如果不是 默认类型,那么需要在这里 声明 import
    import com.zhdelete.targetproj.Person;
    
    interface ITransformerAidlInterface {
    ...
    }
    

    具体见下面完整的ITransformerAidlInterface .aidl 类

    4.将TrasformerService.aidl、Person.aidl复制到客户端的aidl包下。将Person.java复制到客户端java目录,与Server服务端报名相同路径下(如果没有该路径,自己新建)

    最后,服务端 和 客户端 的目录结构如下:

    传递自定义数据类型_server_client_目录结构对照.png

    5.查看是否需要修改build.gradle中sourceSets设置

    代码基本没有变化:

    • Person 类:
    public class Person implements Parcelable {
        String name;
        int age;
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public Person setName(String name) {
            this.name = name;
            return this;
        }
    
        public int getAge() {
            return age;
        }
    
        public Person setAge(int age) {
            this.age = age;
            return this;
        }
    
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(this.name);
            dest.writeInt(this.age);
        }
    
        public Person() {
        }
    
    //    public void readFromParcel(Parcel in) {
    //        name = in.readString();
    //        age = in.readInt();
    //    }
    
        protected Person(Parcel in) {
            this.name = in.readString();
            this.age = in.readInt();
        }
    
        public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
            @Override
            public Person createFromParcel(Parcel source) {
                return new Person(source);
            }
    
            @Override
            public Person[] newArray(int size) {
                return new Person[size];
            }
        };
    }
    
    
    • ITransformerAidlInterface .aidl
    // IMyAidlInterface.aidl
    package com.zhdelete.targetproj;
    
    // Declare any non-default types here with import statements
    //如果不是 默认类型,那么需要在这里 声明 import
    import com.zhdelete.targetproj.Person;
    
    interface ITransformerAidlInterface {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         *
         * 演示一些基本类型,您可以将它们用作参数并在AIDL中返回值。
         */
        void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                double aDouble, String aString);
    
        String provideName();
    
        List<Person> providePersonList();
    }
    
    • Server
    public class TrasformerService extends Service {
        private static String names = "alice & iland";
    
        public TrasformerBinder mTransformerBinder;
    
        private List<Person> personBS = new ArrayList<>();
    
        @Override
        public void onCreate() {
            super.onCreate();
            mTransformerBinder = new TrasformerBinder();
    
            Person p1 = new Person("alice", 23);
            Person p2 = new Person("iland", 18);
            personBS.add(p1);
            personBS.add(p2);
    
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return mTransformerBinder;
    //        return null;
        }
    
    
        public class TrasformerBinder extends ITransformerAidlInterface.Stub {
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
    
            }
    
            @Override
            public String provideName() throws RemoteException {
                return names;
            }
    
            @Override
            public List<Person> providePersonList() throws RemoteException {
                return persons;
            }
    
        }
    }
    

    相关文章

      网友评论

        本文标题:Android Studio使用AIDL-实现进程间通讯

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