AIDL 入门

来源:互联网 发布:c语言函数大全 chm 编辑:程序博客网 时间:2024/06/06 19:39
一。AIDL 的作用    由于 android 的沙箱机制,每一个程序是运行在独立的进程中,每一个进程都有一个独立的 Dalvik VM,即每个进程自行管理内存,独自占有系统资源,并且进程之间是不能进行内存共享的,aidl 的作用就是用来解决进程之间互相通信的问题。    Messenger 是串行的通信方式,AIDL 是并行的通信方式。通信双方一个是 Service 端一个是 Client 端,这种关系是相对的。    在插件化应用中,每一个插件也是一个独立的 apk,相当于一个进程,aidl 很好的解决了不同插件之间的数据交互和通信。二。相关知识2.1 Parcelable 序列化    Parcelable 不同于 SerialLizable 序列化,Serialiable 方式是将整个对象进行序列化,Parcelable 是将一个完整的对象进行分解,分解之后的没一部分都是 Intent 支持传递的数据类型。package com.chris_jason.pluginlibrary;import android.os.Parcel;import android.os.Parcelable;/*** 通信的消息类,实现 Parcelable 接口实现序列化*/public class HMessage implements Parcelable{ //消息内容    private String content;    //进程 id    private int pid;public HMessage(){    }protected HMessage(Parcel in) {    content = in.readString();    pid = in.readInt();}public static final Creator<HMessage> CREATOR = new Creator<HMessage>() {    @Override    public HMessage createFromParcel(Parcel in) {        return new HMessage(in);    }    @Override    public HMessage[] newArray(int size) {        return new HMessage[size];    }};public int getPid() {    return pid;}public void setPid(int pid) {    this.pid = pid;}public String getContent() {    return content;}public void setContent(String content) {    this.content = content;}@Overridepublic int describeContents() {    return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {    dest.writeString(content);    dest.writeInt(pid);}}2.2 Binder

三。实现 aidl 步骤

    新建 aidl 文件,添加自己的接口,sayHello,这个方法返回的是基础数据类型,sayMsg返回的是 HMessage 类型,需要先用 Parcelable 方式实现序列化。aidl 中引用了自定义类型的时候需要在头部导入该类。    ```    // IRemoteService.aidlpackage com.chris_jason.pluginlibrary;//这里导入自定义类型,不然 aidl 文件会构建失败import com.chris_jason.pluginlibrary.HMessage;interface IRemoteService {void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,        double aDouble, String aString);String sayHello();HMessage sayMsg();}```

编写 Service 类,实现 aidl 接口中的方法

package com.chris_jason.pluginlibrary;import android.app.Service;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.Process;import android.os.RemoteException;import android.support.annotation.Nullable;import android.util.Log;/** * Created by mayikang on 17/8/31. */public class RemoteService extends Service {    private String TAG="RemoteService";    @Nullable    @Override    public IBinder onBind(Intent intent) {        Log.e(TAG,"onBind");        //这里代理了 binder        return mBinder;    }    @Override    public void onCreate() {        Log.e(TAG,"onCreate");        super.onCreate();    }    @Override    public void unbindService(ServiceConnection conn) {        Log.e(TAG,"unbindService");        super.unbindService(conn);    }    @Override    public boolean onUnbind(Intent intent) {        Log.e(TAG,"onUnbind");        return super.onUnbind(intent);    }    @Override    public void onDestroy() {        Log.e(TAG,"onDestroy");        super.onDestroy();    }    //在这里实例化了 aidl 接口,返回一个自定义的 binder    public IRemoteService.Stub mBinder=new IRemoteService.Stub() {        @Override        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {        }        @Override        public String sayHello() throws RemoteException {            return "hello-aidl";        }        @Override        public HMessage sayMsg() throws RemoteException {            HMessage msg=new HMessage();            msg.setContent("AIDL-MSG");            msg.setPid(Process.myPid());            return msg;        }    };}

在 manifest 中注册该 service,并且为该 service 开启了一个新的进程:remote,exported:true 表示在其他进程中允许调用该组件,intent 中的 action 是用来过滤请求的
“`

    package com.chris_jason.pluginlibrary;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import com.sctjsj.basemodule.base.ui.act.BaseAppcompatActivity;public class MainActivity extends BaseAppcompatActivity {    private IRemoteService remoteService;    private String TAG="MainActivity";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        findViewById(R.id.say).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent intent=new Intent();                intent.setPackage("com.chris_jason.pluginlibrary");                intent.setAction("com.chris_jason.pluginlibrary.RemoteService");                bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);            }        });        findViewById(R.id.disconnect).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if(mServiceConnection!=null ){                    try{                        unbindService(mServiceConnection);                    }catch (Exception e){                        Log.e("excep",e.toString());                    }                }            }        });    }    @Override    public int initLayout() {        return R.layout.activity_main;    }    @Override    public void reloadData() {    }    ServiceConnection mServiceConnection=new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            Log.e(TAG,"onServiceConnected");            remoteService=IRemoteService.Stub.asInterface(service);            try {                String str=remoteService.sayHello();                HMessage msg=remoteService.sayMsg();                Log.e(TAG,str);                Log.e(TAG,msg.toString());            } catch (RemoteException e) {                e.printStackTrace();            }        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.e(TAG,"onServiceDisconnected");        }    };}

在 logcat 可以看到输出结果,日志会在不同的进程中输出,证明了这次通信是在两个进程之间进行通信的

四。除了这种玩法,还可以在一个工程中建两个 module,并且都指定为 android 工程,而不是 library,这种场景就像 apk1调用 apk2一样。Service 和 Client 的区别在于 Client 中没有 Service 类,Service 的实现 aidl 接口还是在服务端中,其他没有区别。

五。在 Service 和 Client两端进行通信的时候,如果有自定义类型的数据,aidl 文件夹中必须包含和该类同名的 aidl 文件,并且要在使用了该类的aidl 文件中手动导入该类,而且必须要保证两个端中该类的包结构和类名一致,不然会找不到该类

原创粉丝点击