参考
1.AIDL基本操作 —— AIDL
2.使用AIDL进行对象通信
3.AIDL编译时找不到自定义类的解决办法
一个APP要获得另一个APP中的Student的基本信息
1.AIDL文件中非JAVA原始数据类型,都需要导入,并且指明方向 in out inout
2.AIDL编译找不到Student类,要在build.gradle中添加以下代码
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java', 'src/main/aidl']
resources.srcDirs = ['src/main/java', 'src/main/aidl']
aidl.srcDirs = ['src/main/aidl']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
}
}
AIDL (Android Interface Definition Language)是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。
1.建立两个module,一个作为服务端,一个作为客户端。
2.服务端在main文件夹下建立aidl文件夹,在这个文件夹中建立包,包的名字要和Service的包名一样,在包下建立你的.aidl文件,并定义你要暴露的方法。
代码
// AIDLServiceAIDL.aidl
package com.android.tongs.aidl;
// Declare any non-default types here with import statements
import com.android.tongs.aidl.Student;
// non-JAVA primtive parameter must indicate its direction , in out inout
interface AIDLServiceAIDL {
/** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString);
void setData(String data);
/** * 注意非原始类型要声明方向in inout out */
void addStudent(inout Student student);
List<Student> getStudents();
}
3.建立Student.java,和AIDL文件一个目录,Student类要实现Paraleable接口,以序列化
package com.android.tongs.aidl;
import android.os.Parcel;
import android.os.Parcelable;
/** * Created by tongs on 2016/4/1. * email:[email protected] */
public class Student implements Parcelable{
private String name;
private int id;
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 Student() {
}
public Student(String name, int id) {
this.name = name;
this.id= id;
}
protected Student(Parcel in) {
readFromParcel(in);
}
public static final Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getName());
dest.writeInt(getId());
}
public Student readFromParcel(Parcel in){
return new Student(in.readString(),in.readInt());
}
@Override
public String toString() {
return "姓名:"+this.name+"id:"+this.id;
}
}
4.建立Student.aidl,再此文件中声明Studeng是AIDL的序列化类型
// Student.aidl
package com.android.tongs.aidl;
parcelable Student;
5.建立服务,服务里onbind返回一个Stub,Stub实质上是一个继承了IBinder的普通类,客户端获取到此Binder后可进行对应的操作。
package com.android.tongs.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class AIDLService extends Service {
private String data = "默认的数据";
private boolean running1 = false;
private boolean running2 = false;
private String PCK_NAME= "com.android.tongs.aidltest";
private List<Student> students = new ArrayList<>();
public AIDLService() {
}
/** * @return 向另一个app暴露AIDL接口 */
@Override
public IBinder onBind(Intent intent) {
System.out.println("onBind调用");
return new AIDLServiceAIDL.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public void setData(String data) throws RemoteException {
AIDLService.this.data = data;
}
@Override
public void addStudent(Student student) throws RemoteException {
synchronized (students) {
if (!students.contains(student)) {
students.add(student);
}
}
}
@Override
public List<Student> getStudents() throws RemoteException {
return students;
}
/** * 权限验证,不是指定的包不让开启服务 * @return * @throws RemoteException */
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
String packageName;
packageName = AIDLService.this.getPackageManager().getPackagesForUid(getCallingUid())[0];
Log.i("==", packageName);
if(!packageName.equals(PCK_NAME))
return false;
return super.onTransact(code,data,reply,flags);
}
};
}
@Override
public boolean onUnbind(Intent intent) {
System.out.println("onUnBind调用");
return false;
}
@Override
public void onCreate() {
super.onCreate();
running1 = true;//代表线程在运行
running2 = true;
students.add(new Student("张三",1));
new Thread("app之间传递数据") {
@Override
public void run() {
while (running1) {
try {
Thread.sleep(1000);
System.out.println("传递数据:"+data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread("app之间通过Parcelable传递对象"){
@Override
public void run() {
while (running2) {
try {
Thread.sleep(1000);
System.out.println("传递对象:"+students.get(0).toString());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
System.out.println("startService");
}
@Override
public void onDestroy() {
super.onDestroy();
running1 = false;
running2 = false;
System.out.println("destroyService");
}
}
6.将aidl下的文件连同aidl文件夹拷到客户端的main下,因为客户端要通过aidl将pacel中的数据返回成对象。
7.客户端在Onconnection中获取中获取到Stub对象,并通过内部方法asInterface转换为IBinder,进而与服务进行通信
public ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = AIDLServiceAIDL.Stub.asInterface(service);
System.out.println("Connect Service");
}
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("Disconnect Service");
}
};
客户端获取到了Student,但是获取不到其的属性,id为默认的0,name为null,序列化的问题也排除了,不知道是哪里出现了问题。
AIDL实质是想客户端暴露接口Stub,客户端获取此Stub就能调用其中的方法,实现与服务的通信。
ADIL分支 https://github.com/tongsdroid/LearnAndroid