IPC机制之了解AIDL(一)

   日期:2020-11-05     浏览:99    评论:0    
核心提示: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


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

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服