IPC机制之了解AIDL(一)

IPC机制(一)了解AIDL

AIDL了解

AIDL这门语言的目的就是为了实现进程间通信。在Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL就是为了满足这种需求而诞生的。通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求 。
aidl主要分为服务端与客户端两方面:
服务端
服务端首先创建一个Service监听客户端的连接请求,创建一个aidl文件,在service中实现,并暴露给客户端。
客户端
客户端主要绑定服务端的Service,将Binder对象转成aidl类型,就可以调用服务端的实现方法。

AIDL支持的数据类型
1.基本数据类型: int、long、float、double、boolean等(不包含short:aidl不支持short,因为Parcel没有办法对short进行序列化,也就没办法通过aidl将short类型在客户端与服务端进行传递)
2.String,CharSequence
3.实现了Parcelable接口的数据类型
4.List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
5.Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象

AIDL文件可以分为两类。一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用,定向Tag就是用来标注这些方法的参数值

定向Tag定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分为 in、out、inout 三种。其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。此外,如果AIDL方法接口的参数值类型是:基本数据类型、String、CharSequence或者其他AIDL文件定义的方法接口,那么这些参数值的定向 Tag 默认是且只能是 in,所以除了这些类型外,其他参数值都需要明确标注使用哪种定向Tag。

明确导包在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下

代码较乱,kotlin和java都有…多多包涵

服务端代码

aidl接口创建

在这里插入图片描述
创建Aidl文件

// IMyAidlInterface.aidl
package com.example.aidl;
parcelable Student;
// Declare any non-default types here with import statements

interface IMyAidlInterface {

   String getName();

   Student getStudent();

   void setName( String name);

   void setStudent(in Student stu);

   void setOutName( out Student stu);

   void setInOutName(inout Student stu);

   void setDefaultName(  String name);
}

创建Student类(需要实现Parcelable接口)

package com.example.aidl

import android.os.Parcel
import android.os.Parcelable

/**
 * Created by Android Studio
 * Date: 2020/11/2
 * Time: 11:09
 */
class Student() : Parcelable {
    var name: String? = null
    var old = 0

    constructor(parcel: Parcel) : this() {
        name = parcel.readString()
        old = parcel.readInt()
    }

    fun readFromParcel(`in`: Parcel) {
        name = `in`.readString()
        old = `in`.readInt()
    }

    override fun toString(): String {
        return "name=" + name + "-------" + "old=" + old
    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(name)
        parcel.writeInt(old)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Student> {
        override fun createFromParcel(parcel: Parcel): Student {
            return Student(parcel)
        }

        override fun newArray(size: Int): Array<Student?> {
            return arrayOfNulls(size)
        }
    }


}

readFromParcel()方法需要自己加进去,否则转换会报错。当然,也要有默认构造器。否则后续可能会出现错误。

rebuild工程
更改aidl文件需要重新build一下,系统自动重新生成新的IMyAidlInterface,以及内部抽象Stub类,内部类Proxy等。

创建服务端Service:

package com.example.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import com.example.aidl.IMyAidlInterface;
import com.example.aidl.Student;

public class MyService extends Service {

    private static final String TAG = "MyService";

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        if (intent != null) {
            Log.e(TAG, "onBind this hash code = " + this.hashCode());
            Log.e(TAG, "intent from = " + intent.getStringExtra("from"));
        }
        return myBinder;
    }

    public static MyBinder myBinder = new MyBinder();

    static class MyBinder extends IMyAidlInterface.Stub {
        String name;
        Student student;

        @Override
        public String getName() {
            return name;
        }

        @Override
        public void setName(String name) throws RemoteException {
            this.name = name;
        }

        @Override
        public Student getStudent() throws RemoteException {
            if (student != null) {

                Log.e(TAG, "getStudent: " + this.student.toString());
            } else {
                Log.e(TAG, "getStudent: ==null");
            }
            return student;
        }

        @Override
        public void setStudent(Student stu) throws RemoteException {
            Log.e(TAG, "studentIn: 服务端收到参数属性"+stu.toString() );
            this.student = stu;
            stu.setName("service in change");
            Log.e(TAG, "studentIn: " + stu.hashCode());
        }


        @Override
        public void setOutName(Student stu) throws RemoteException {
            Log.e(TAG, "studentOut: 服务端收到参数属性"+stu.toString() );
            student = stu;
            stu.setName("service out change");
            Log.e(TAG, "studentOut: " + stu.hashCode());
        }

        @Override
        public void setInOutName(Student stu) throws RemoteException {
            Log.e(TAG, "studentInOut: 服务端收到参数属性"+stu.toString() );
            student = stu;
            stu.setName("service InOut change");
            Log.e(TAG, "studentInOut: " + stu.hashCode());
        }

        @Override
        public void setDefaultName(String name) throws RemoteException {
            this.name = name;
        }


    }
}

声明service 的action,由于跨进程,需要隐式启动服务。

      <service
            android:name="com.example.service.MyService"

            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.service.MyService" />
            </intent-filter>
        </service>

启动服务
服务端启动服务或者绑定服务都可以

(最开始以为是必须的,后面好像发现不启动是不是也行?有点怪,毕竟通讯嘛,都启动吧,哈哈)。

 ser = object : ServiceConnection {
            override fun onServiceDisconnected(name: ComponentName?) {

            }

            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                interfaceA = IMyAidlInterface.Stub.asInterface(service)
            }

        }

        var intent = Intent(this, MyService::class.java);
        intent.putExtra("from", "AidlTestActivity")
        bindService(intent, ser, Context.BIND_AUTO_CREATE)

客户端代码

将aidl文件以及序列化类粘贴至服务端(保持包名相同)
在这里插入图片描述

绑定服务,连接远程服务端

     ser = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.e("TAGwcz", "onServiceConnected: ");
                interfaceA = IMyAidlInterface.Stub.asInterface(service);


            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };
        Intent intent = new Intent();
        intent.setAction("com.example.service.MyService");
        intent.setPackage("com.example.aidlservice");
        intent.putExtra("from", "MainActivity");
        bindService(intent, ser, Context.BIND_AUTO_CREATE);
     aidl_change1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    studentOut = new Student("client  out Student", 1);
                    Log.e(TAG, "onClick:before studentOut.hashCode()=="+studentOut.hashCode() );
                    interfaceA.setOutName(studentOut);
                    Log.e(TAG, "onClick:after studentOut.hashCode()=="+studentOut.hashCode() );

                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        aidl_change2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    studentInOut = new Student("client  inout Student", 2);
                    Log.e(TAG, "onClick:before studentInOut.hashCode()=="+studentInOut.hashCode() );

                    interfaceA.setInOutName(studentInOut);
                    Log.e(TAG, "onClick:after studentInOut.hashCode()=="+studentInOut.hashCode() );
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        aidl_change3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    studentIn = new Student("client  in Student", 3);
                    Log.e(TAG, "onClick:before studentIn.hashCode()=="+studentIn.hashCode() );
                    interfaceA.setStudent(studentIn);
                    Log.e(TAG, "onClick:after studentIn.hashCode()=="+studentIn.hashCode() );
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });

这样就可以双向通信了。

aidl小例子

IPC机制之了解AIDL(二)了解定向TAG

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值