Android高手进阶(一)AIDL跨进程调用
什么是ADIL跨进程调用?
由于Android是不允许两个进程共享内存空间的,所以如果当前你开发的应用需要调用其他应用的某个逻辑处理某个事情的时候,就需要用到AIDL跨进程调用。
AIDL能干什么?
APP与APP之间的逻辑交互
AIDL开发的步骤?
服务端
一.新建一个AIDL文件
二.定义接口方法
// IMyAidlInterface.aidl
package com.tcl.personalcloudaidljar;
import com.tcl.personalcloudaidljar.StudentModel;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
double doCalulate(double a,double b);
double doMin(double a, double b);
void setStudent(in StudentModel model);
StudentModel getFinalStudent(inout StudentModel model);
List<StudentModel> getStudentResult(inout List<StudentModel> model);
}
可以传的值有JAVA基本类型和List、Map,其他自定义类型的Model需要指明是in、out、inout之中的一种,分别表示输入、输出、和同时输入和输出。
如果是自定义类型的Model,需要序列化,实现Parcelable或者Serializable接口,建议实现Parcelable接口(效率更高)。
还需要定义一个Model类名一样的aidl接口,内容为
// Student.aidl
package com.tcl.personalcloudaidljar;
parcelable StudentModel;
Model类的具体实现见下图
package com.tcl.personalcloudaidljar;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by pcgu on 16-2-1.
*/
public class StudentModel implements Parcelable {
private int id;
private String name;
private long md5;
private boolean canShow;
public StudentModel() {
}
private StudentModel(Parcel in) {
readFromParcel(in);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public long getMd5() {
return md5;
}
public void setMd5(long md5) {
this.md5 = md5;
}
public boolean isCanShow() {
return canShow;
}
public void setCanShow(boolean canShow) {
this.canShow = canShow;
}
public static final Creator<StudentModel> CREATOR =
new Creator<StudentModel>() {
@Override
public StudentModel createFromParcel(Parcel source) {
return new StudentModel(source);
}
@Override
public StudentModel[] newArray(int size) {
return new StudentModel[size];
}
};
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
dest.writeLong(md5);
dest.writeByte((byte) (canShow ? 1 : 0));
}
@Override
public int describeContents() {
return 0;
}
public void readFromParcel(Parcel in) {
id = in.readInt();
name = in.readString();
md5 = in.readLong();
canShow = in.readByte() != 0;
}
}
所有自定义的Model类必须在aidl类中申明。
三.实现service类
package com.tcl.personalcloudaidljar;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.List;
/**
* Created by pcgu on 16-1-29.
*/
public class MyService extends Service {
private static final String TAG = "TEST";
private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
@Override
public double doCalulate(double a, double b) throws RemoteException {
Log.e(TAG, "doCalulate a and b=" + a + "," + +b);
return a + b;
}
@Override
public double doMin(double a, double b) throws RemoteException {
return a - b;
}
@Override
public void setStudent(StudentModel model) throws RemoteException {
Log.e(TAG, "setStudent id =" + model.getId() + " name=" + model.getName() +
" md5=" + model.getMd5() + " canShow=" + model.isCanShow());
}
@Override
public StudentModel getFinalStudent(StudentModel model) throws RemoteException {
Log.e(TAG, "getFinalStudent id =" + model.getId() + " name=" + model.getName() +
" md5=" + model.getMd5() + " canShow=" + model.isCanShow());
model.setName("gupengcheng");
return model;
}
@Override
public List<StudentModel> getStudentResult(List<StudentModel> model) throws RemoteException {
Log.e(TAG, "get Student Result =" + model.get(0).getName() +
" size ==" + model.size());
StudentModel singleModel = new StudentModel();
singleModel.setName("gugugu");
singleModel.setCanShow(false);
singleModel.setId(123);
singleModel.setMd5(1234566);
model.add(singleModel);
return model;
}
};
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "MyService onCreate");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "MyService onDestroy");
}
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
Log.e(TAG, "MyService onRebind");
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "MyService onUnbind");
return super.onUnbind(intent);
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "MyService onBind");
return mBinder;
}
}
service类中最重要的是实现IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub()抽象类,并且在onBind中返回这个mBinder。
四.在manifest中申明改service并指定过滤条件
这里指定的过滤条件是action为com.tcl.personalcloudaidljar.aidl。
客户端
客户端也就是调用方,调用刚才的服务端的service中实现的抽象方法来完成某个逻辑。
一.拷贝服务端的aidl包到服务端
这时候make project一次就会在如下目录中自动生成一个aidl实现类
二.调用服务端的aidl接口的具体实现方法
有两种使用方式,分别是activity中直接使用和封装成Jar包给第三方使用。
(1)直接使用
bindService,然后通过AIDL类的对象调用service中的具体方法来达到跨进程调用的目的。需要注意的是调用之前必须bindService,在Activity onDestory的时候必须unbindService.
(2)封装成jar包,实现类如下
package com.tcl.personalcloudaidlclient;
import android.annotation.TargetApi;
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.util.Log;
import com.tcl.personalcloudaidljar.IMyAidlInterface;
import com.tcl.personalcloudaidljar.StudentModel;
import java.util.ArrayList;
import java.util.List;
/**
* Created by pcgu on 16-2-1.
*/
public class PersonalCloudManager {
private static final String TAG = "PersonalCloudManager";
private IMyAidlInterface mIMyAidlInterface;
private static boolean connected = false;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG, "client onServiceConnected");
mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
connected = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "client onServiceDisconnected");
mIMyAidlInterface = null;
connected = false;
}
};
@TargetApi(4)
public void bindAidlService(Context context) {
Intent intent = new Intent();
intent.setAction("com.tcl.personalcloudaidljar.aidl");
intent.setPackage("com.tcl.personalcloudaidljar");
context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
public void unbindAidlService(Context context) {
context.unbindService(connection);
}
public double doCalculate(double num1, double num2) {
if (!connected) {
return 0;
}
double result = 0;
try {
result = mIMyAidlInterface.doCalulate(num1, num2);
Log.e(TAG, "client add result ==" + result);
} catch (RemoteException e) {
e.printStackTrace();
}
return result;
}
public double doMin(double num1, double num2) {
if (!connected) {
return 0;
}
double result = 0;
try {
result = mIMyAidlInterface.doMin(num1, num2);
Log.e(TAG, "client min result ==" + result);
} catch (RemoteException e) {
e.printStackTrace();
}
return result;
}
public void setStudentModel(StudentModel model) {
if (!connected) {
return;
}
try {
mIMyAidlInterface.setStudent(model);
Log.e(TAG, "client set Student Model");
} catch (RemoteException e) {
e.printStackTrace();
}
}
public StudentModel getFinalStudentModel(StudentModel model) {
if (!connected) {
return model;
}
StudentModel finalStudentModel = new StudentModel();
try {
finalStudentModel = mIMyAidlInterface.getFinalStudent(model);
Log.e(TAG, "client set final Student Model");
} catch (RemoteException e) {
e.printStackTrace();
}
return finalStudentModel;
}
public List<StudentModel> getList(List<StudentModel> model) {
if (!connected) {
return model;
}
List<StudentModel> models = new ArrayList<>();
try {
models = mIMyAidlInterface.getStudentResult(model);
Log.e(TAG, "client set final Student Model");
} catch (RemoteException e) {
e.printStackTrace();
}
return models;
}
public boolean isServiceConnected() {
return connected;
}
}
需要注意的是给第三方调用需要提供一个服务绑定成功与否的标志位,即connected这个参数,第三方才知道能否调用AIDL的实现方法,只有为True的时候才能调用。
三.封装成Jar包的方法
在app的build.gradle中添加
task makeJar(type: Copy) {
delete 'build/libs/aidlsdk.jar'
from('build/intermediates/bundles/release/')
into('build/libs/')
include('classes.jar')
rename ('classes.jar', 'aidlsdk.jar')
}
makeJar.dependsOn(build)
用打包命令 ./gradlew makeJar 即可打包为红色标记的名字的jar包
四.注意问题
当aidl方法中参数为回调接口的时候,调用实现类需要用new ***Callback.stub()的方式