AIDL——Android接口定义语言初步探索

来源:互联网 发布:csgo脚本优化 编辑:程序博客网 时间:2024/06/06 17:47

前言
这几天项目不是特别的忙,想在Android技术方面寻求突破,就在网上搜索AIDL是什么,也看了几篇关于AIDL的博客,现在想把自己对AIDL的理解记录下来。

AIDL(Android Interface Definition Language)即Android接口定义语言,主要作用于跨进程通信;对于在Android里的应用,在应用层,简单点就是一款APP能够使用另一款APP提供的服务(service),通过传递参数,或者调用方法来完成需求。

接下来说一下怎么使用AIDL(AS开发工具):

服务器端

  • 数据对象——这个对象包含了我们需要用到的数据信息
    在java目录下新建一个InfoBean.java文件,声明两个变量name和age,添加set和get方法,该类要实现Parcelable接口。
public class InfoBean implements Parcelable {    private String name;    private int age;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString() {        return "InfoBean{" +                "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 void readFromParcel(Parcel dest){//该方法自己需要手动添加        name=dest.readString();        age=dest.readInt();    }    public InfoBean() {    }    protected InfoBean(Parcel in) {        this.name = in.readString();        this.age = in.readInt();    }    public static final Creator<InfoBean> CREATOR = new Creator<InfoBean>() {        @Override        public InfoBean createFromParcel(Parcel source) {            return new InfoBean(source);        }        @Override        public InfoBean[] newArray(int size) {            return new InfoBean[size];        }    };}

这里推荐使用Android Parcelable code generator 插件自动完成Parcelable 的实现。
这里写图片描述
插件安装完成后需要重启AS才能生效。使用插件:
把光标停在需要实现Parcelable的类上,按Alt+Insert,选择Parcelable,在弹窗里把所有的全部选中,ok
这里写图片描述
完成一系列操作后还需要手写readFromParcel方法,因为数据双向通信,readFromParcel方法和writeToParcel方法相似,一个是读数据,一个是写数据,照着写就可以了,顺序要一样。

  • 新建AIDL文件
    在main目录下新建aidl文件夹,在aidl文件夹中新建一个包,包名与上面数据对象InfoBean.java的包名要一样,在包下新建两个aidl文件,InfoBean.aidl和InfoManager.aidl
    这里写图片描述

InfoBean.aidl引入InfoBean对象为其他aidl文件使用

// Info.aidl//这个文件的作用是引入了一个序列化对象 InfoBean 供其他的AIDL文件使用//注意:InfoBean.aidl与InfoBean.java的包名应当是一样的package com.aidl.server;parcelable InfoBean;

InfoManager.aidl文件声明要实现的几个方法

package com.aidl.server;// Declare any non-default types here with import statementsimport com.aidl.server.InfoBean;//引入定义的aidl文件,使用序列化对象,interface InfoManager {    /**     * Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */     //下面定义几个接口要实现的方法      void addInfo(in InfoBean info);      InfoBean getInfo(in int i);      List<InfoBean> getAllInfo();      void changeInfo(in InfoBean inInfo,out InfoBean outInfo,inout InfoBean inoutInfo);}

定义的方法参数前面的in、out、inout是什么意思
它们表示数据流向,在AIDL语言规则中,java数据基本类型和String 都默认是in并且只能是in,非基本类型数据需要指定数据流向:
in:表示服务端接收从客户端传过来的数据,当在服务端改变参数时,客户端对象变量不变。
out:表示服务端不会接收客户端传过来的数据对象,服务端会新建一个数据对象,回传给客户端,同时改变客户端参数的值。
inout:表示服务端接收客户端传过来的对象,改变属性后,客户端对象的属性同样改变。

Rebuild 工程会在app\build\generated\source\aidl\debug\com\aidl\server目录下自动生成InfoManager.java文件,点开可以看一下具体是怎么写的,这里不做解释

  • 服务service
    前期准备工作做好了,可以开始写服务代码了,新建一个类继承Service
public class AIDLService extends Service {    List<InfoBean> Infos=new ArrayList<InfoBean>();    private final InfoManager.Stub mInfoManager=new InfoManager.Stub(){//通过InfoManager.Stub新建一个对象,实现自己定义的几个方法,共其他进程调用        @Override        public void addInfo(InfoBean info) throws RemoteException {            if(Infos==null){                Infos=new ArrayList<InfoBean>();            }            if(info==null)return;            Infos.add(info);            Log.e("ServerAdd",Infos.toString());        }        @Override        public InfoBean getInfo(int i) throws RemoteException {            if(Infos==null){                Log.e("ServerGetInfo","Info is null");                return null;            }            if(i>=Infos.size()){                Log.e("ServerGetInfo","下标越界");                return null;            }            return Infos.get(i);        }        @Override        public List<InfoBean> getAllInfo() throws RemoteException {            if(Infos==null){                Log.e("ServerGetInfo","Info is null");                return null;            }            return Infos;        }        @Override        public void changeInfo(InfoBean inInfo, InfoBean outInfo, InfoBean inoutInfo) throws RemoteException {            inInfo.setAge(100);            outInfo.setAge(100);            inoutInfo.setAge(100);            Log.e("ServerinInfo",inInfo.toString());            Log.e("ServeroutInfo",outInfo.toString());            Log.e("ServerinoutInfo",inoutInfo.toString());        }    } ;    @Override    public void onCreate() {        super.onCreate();        InfoBean info=new InfoBean();        info.setAge(25);        info.setName("JY");        Infos.add(info);    }    @Nullable    @Override    public IBinder onBind(Intent intent) {//通过bindService启动服务,获得对象。        return mInfoManager;    }}

最后在AndroidManifest.xml中声明服务

<service android:name=".AIDLService"            android:exported="true">            <intent-filter>                <action android:name="com.aidl.server">                </action>                <category android:name="android.intent.category.DEFAULT"></category>            </intent-filter>        </service>

添加action以便外界启动服务

  • 客户端代码
    首先,把数据对象和aidl文件移植到客户端项目,注意数据对象和aidl文件的包名要和服务端的包名一样

Rebuild 工程后就可以声明一个InfoManager对象,对象的赋值通过启动service返回的IBuild构建

 mInfoManager=InfoManager.Stub.asInterface(service);

client代码

public class MainActivity extends AppCompatActivity {    private boolean isServerStart=false;    private InfoManager mInfoManager;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Button btn=(Button)findViewById(R.id.button);        btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                try {                    sendMessage();                } catch (RemoteException e) {                    e.printStackTrace();                }            }        });    }    private void sendMessage() throws RemoteException {        if(!isServerStart){            BindService();            return;        }        InfoBean info=new InfoBean();        info.setAge(50);        info.setName("张三");        mInfoManager.addInfo(info);        List<InfoBean> infos=mInfoManager.getAllInfo();        Log.e("ClientGetAllInfo",infos.toString());        InfoBean bean=mInfoManager.getInfo(0);        Log.e("ClientGetInfo",bean.toString());        InfoBean info1=new InfoBean();        info1.setAge(10);        info1.setName("李四");        InfoBean info2=new InfoBean();        info2.setAge(20);        info2.setName("王五");        mInfoManager.changeInfo(info,info1,info2);        Log.e("ClientTagin",info.toString());        Log.e("ClientTagout",info1.toString());        Log.e("ClientTaginout",info2.toString());    }    @Override    protected void onStart() {        super.onStart();        if(!isServerStart){            BindService();        }    }    @Override    protected void onStop() {        super.onStop();        if(isServerStart){            unbindService(mServiceConnection);        }    }    private void BindService() {        Intent intent = new Intent();        intent.setAction("com.aidl.server");//servcie action        intent.setPackage("com.aidl.server");//服务端app包名        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);    }    private ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            Log.e("Client","Server连接成功");            mInfoManager=InfoManager.Stub.asInterface(service);            isServerStart=true;        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.e("Client","Server断开连接");            isServerStart=false;        }    };}

最后运行结果:

  • 服务端
    这里写图片描述
  • 客户端
    这里写图片描述

到这里AIDL的初步探索就结束了,原理什么的都不太懂,用的时候应该就是这样吧,可以根据项目的需求做出改进。

参考

有不对的地方,请大神指证!!!

原创粉丝点击