既然是进程间通信,肯定会有服务端和客户端
一、服务端
1、在服务端我们首先定义一个提供服务的AIDL接口文件:IMyAidlInterface.aidl以及根据需求自定义了一个Worker的数据类型,如下图:(注意aidl包与java包是在同一级目录)
aidl文件的书写方式很简单其中Worker.aidl内容如下:
// Worker.aidl
package com.zui.lib.data;
// 自定义数据类型
parcelable Worker;
IMyAidlInterface.aidl如下:
// IMyAidlInterface.aidl
package com.zui.lib;
import com.zui.lib.data.Worker; // 注意自定义的类一定要import,即使该类与此文件在同一个包同一级目录下也要导入
interface IMyAidlInterface {
String getName();
void setName(String name); // aidl默认支持的数据类型定向tag必须是in,书写时可以省略
void setWorker(in Worker worker);
Worker getWorker(out Worker worker);
Worker modifyWorker(inout Worker worker);
}
2、接下来需要书写服务端的java文件
首先是自定义的Worker数据类型Worker.java(注意需要Parcelable 接口)
package com.zui.lib.data;
import android.os.Parcel;
import android.os.Parcelable;
public class Worker implements Parcelable {
String mName;
int mAge;
String mJob;
public Worker() {
}
public Worker(String mName, int mAge, String mJob) {
this.mName = mName;
this.mAge = mAge;
this.mJob = mJob;
}
public Worker(Parcel source) {
mName = source.readString();
mAge = source.readInt();
mJob = source.readString();
}
public String getName() {
return mName;
}
public void setName(String mName) {
this.mName = mName;
}
public int getAge() {
return mAge;
}
public void setAge(int mAge) {
this.mAge = mAge;
}
public String getJob() {
return mJob;
}
public void setJob(String mJob) {
this.mJob = mJob;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mName);
dest.writeInt(mAge);
dest.writeString(mJob);
}
public void readFromParcel(Parcel in){
// mName = in.readString();
// mAge = in.readInt();
// mJob = in.readString();
}
public static final Creator CREATOR = new Creator() {
@Override
public Worker createFromParcel(Parcel source) {
return new Worker(source);
}
@Override
public Worker[] newArray(int size) {
return new Worker[0];
}
};
@Override
public String toString() {
return "Worker{" +
"mName='" + mName + '\'' +
", mAge=" + mAge +
", mJob='" + mJob + '\'' +
'}';
}
}
注意Worker.aidl与worker.java包名目录层级要一致:例如本文com.zui.lib.data
然后创建一个MyService继承Service,在MyService中实现我们定义的IMyAidlInterface接口
package com.zui.aidltest;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.zui.lib.IMyAidlInterface;
import com.zui.lib.data.Worker;
public class MyService extends Service {
String TAG = "AIDL MyService";
public static Worker publicWorker = null;
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder(); // 返回自定义的Binder对象吗(客户端绑定service的时候,服务端会将此对象提供给客户端,拿到此对象后客户端就可以享受服务端提供的服务了)
}
class MyBinder extends IMyAidlInterface.Stub{ // 实现IMyAidlInterface接口中的方法
@Override
public String getName() throws RemoteException {
return "this is test name";
}
@Override
public void setName(String name) throws RemoteException {
publicWorker.setName(name);
}
@Override
public void setWorker(Worker worker) throws RemoteException {
publicWorker = worker;
Log.d(TAG,"setWorker : worker = " + worker);
}
@Override
public Worker getWorker(Worker worker) throws RemoteException {
return publicWorker;
}
@Override
public Worker modifyWorker(Worker worker) throws RemoteException {
publicWorker = worker;
return publicWorker;
}
}
}
至此,服务端就算编写完成了,下面介绍客户端app中的实现
二、客户端
1、客户端也需要重复定义服务端的aidl文件,注意客户端的aidl文件要与服务端保持完全一致,所以这里我就直接将服务端的的aidl文件夹拷贝到客户端,同时为了满足自定义的数据类型包名目录层级与aidl中定义的一致,同时将服务端的自定义数据类型java文件也拷贝到客户端,如下图
2、编写MainActivity绑定服务,与服务端进行通信
package com.zhf.aidlclient; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import com.zui.lib.IMyAidlInterface; import com.zui.lib.data.Worker; public class MainActivity extends AppCompatActivity { String TAG = "AIDL MainActivity"; private IMyAidlInterface mIMyAidlInterface; private MyServiceConnection mMyServiceConnection; Worker mWorker; private class MyServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { //绑定成功回调 Log.d(TAG,"onServiceConnected"); mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); //获取服务端提供的接口 try { Log.d(TAG,mIMyAidlInterface.getName()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMyServiceConnection = new MyServiceConnection(); ComponentName componentName = new ComponentName("com.zui.aidltest","com.zui.aidltest.MyService"); // 服务端app的service Intent intent = new Intent(); intent.setComponent(componentName); intent.setAction("android_bind_service"); boolean bind = bindService(intent,mMyServiceConnection,BIND_AUTO_CREATE); // 绑定服务端的service Log.d(TAG,"bind = "+ bind); } public Worker getWorker(View view) throws RemoteException { Log.d(TAG,"getWorker"); return mIMyAidlInterface.getWorker(new Worker("worker_1",0,"get")); // 获取服务端的数据,与服务端通信 }; public void setWorker(View view) throws RemoteException { Log.d(TAG,"setWorker"); mWorker = new Worker("worker_1",1,"set"); mIMyAidlInterface.setWorker(mWorker); // 与服务端通信 }; public Worker modifyWorker(View view) throws RemoteException { Log.d(TAG,"modifyWorker"); mWorker = new Worker("worker_2",2,"modify"); return mIMyAidlInterface.modifyWorker(mWorker); // 与服务端通信 }; @Override protected void onDestroy() { unbindService(mMyServiceConnection); // 记得解绑service,否则会引起泄漏 super.onDestroy(); } }
到这客户端也编写完成了,接下来就是客户端利用服务端提供的接口与服务端进行通信了