Android Notes 之 AIDL

参考
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

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

你可能感兴趣的:(android,通信,service,aidl)