AIDL 入门

xiaoxiao2021-02-28  117

一。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; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(content); dest.writeInt(pid); } } 2.2 Binder

三。实现 aidl 步骤

新建 aidl 文件,添加自己的接口,sayHello,这个方法返回的是基础数据类型,sayMsg返回的是 HMessage 类型,需要先用 Parcelable 方式实现序列化。aidl 中引用了自定义类型的时候需要在头部导入该类。 ``` // IRemoteService.aidl package 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 文件中手动导入该类,而且必须要保证两个端中该类的包结构和类名一致,不然会找不到该类

转载请注明原文地址: https://www.6miu.com/read-37526.html

最新回复(0)