AIDL使用

最近有空就在看IPC,正好路过AIDL这里,发现基本忘干净了…正好借此机会回顾并记录下来,那么接下来我就先撸为敬了.

AIDL用来做什么

AIDL(Android 接口定义语言)与您可能使用过的其他 IDL 类似。 您可以利用它定义客户端与服务使用进程间通信 (IPC) 进行相互通信时都认可的编程接口。 在 Android 上,一个进程通常无法访问另一个进程的内存。 尽管如此,进程需要将其对象分解成操作系统能够识别的原语,并将对象编组成跨越边界的对象。 编写执行这一编组操作的代码是一项繁琐的工作,因此 Android 会使用 AIDL 来处理。

上面是文档中的描述,通俗的说法:AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service并可以拿到它暴露给你的方法获取数据,这样你的APP可以和其他APP交互。

AIDL使用

上面已经说过AIDL是用来将对象分解成操作系统能够识别的原语,并将对象编组成跨越边界的对象,那么这里就按AIDL中可以使用的数据类型来分别说明如何使用.

基本类型

因为AIDL是两个APP交互啦,所以当然要两个APP啦,我们在第一个工程目录右键

输入名字AS就帮我们新建了AIDL文件了

// IMyName.aidl
package com.zly.www.test1;

// Declare any non-default types here with import statements

interface IMyName {
    /**
     * 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);
}

这里basicTypes这个方法其实没啥用可以删掉,但从他注释里面可以看出,AIDL默认支持int,long,boolean,float,double,String基本类型的数据.因为这里是要跨进程通讯的,所以不是随便你自己定义的一个类型就可以在AIDL使用的,自定义类型我们在后面会讲.我们在AIDL文件中定义一个我们要提供给第二个APP使用的接口.

那么我们把这个类稍微修改下

// IMyName.aidl
package com.zly.www.test1;

// Declare any non-default types here with import statements

interface IMyName {

    String getName();

}

然后点下sycn project让AS帮我们生成下aidl代码.

接下来我们新建一个service并且在清单注册,然后在service中新建一个内部类MyBinder继承刚刚写的AIDL接口IMyName里的Stub类并实现方法,在onBind()返回该实例,你可能会问我没在IMyName里写Stub类呀,其实这里Stub是AS根据刚刚AIDL文件生成的代码中的.

public class MyService extends Service {

    private MyBinder mBinder = new MyBinder();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    class MyBinder extends IMyName.Stub{

        @Override
        public String getName() throws RemoteException {
            return "帅也是错吗";
        }
    }
}

接下来新建一个项目,将前面写的AIDL文件拷贝过来,要注意的是包名必须完全一致.

syncProject一下项目,然后在MainActivity中绑定service

public class MainActivity extends AppCompatActivity {

    private IMyName iMyName;
    private ServiceConnection serviceConnection;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent("aaaa");
        intent.setPackage("com.zly.www.test1");
        bindService(intent, serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iMyName = IMyName.Stub.asInterface(service);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                iMyName = null;
            }
        }, BIND_AUTO_CREATE);

    }

    public void get(View v) {
        try {
            Toast.makeText(this, iMyName.getName(), Toast.LENGTH_SHORT).show();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }
}

这边我们通过隐式意图来绑定service,在onServiceConnected方法中通过IMyName.Stub.asInterface(service)获取IMyName对象,然后在get()中调用IMyName.getName()。(这里有点需要注意Android 5.0出后,其中有个特性就是Service Intent must be explitict,也就是说从Lollipop开始,service服务必须采用显示方式启动,所以这里intent我指定了package)

自定义类型

如果要在AIDL中使用自定义类型的数据,第一自定义类型要实现Parcelable接口,第二需要写一个ADIL声明文件.

下面创建一个Student类实现Parcelable接口

public class Student implements Parcelable {

    public Student(String name) {
        this.name = name;
    }

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    protected Student(Parcel in) {
        name = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    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];
        }
    };

}

接下来新建一个aidl文件,名称为我们自定义类型的名称,这边是Student.aidl。在Student.aidl申明我们的自定义类型和它的完整包名,注意这边parcelable是小写的,不是Parcelable接口,一个自定类型需要一个这样同名的AIDL文件来声明。

package com.zly.www.test1;
parcelable Student;

然后在我们的aidl接口中导入自定义数据类型

syncProjcet,然后在service中实现接口方法

class MyBinder extends IMyName.Stub{

        @Override
        public String getName() throws RemoteException {
            return "帅也是错吗";
        }

        @Override
        public Student getStudent() throws RemoteException {
            return new Student("朱利源");
        }
    }

然后把AIDL文件与自定义类型文件拷到第二个项目,注意这里还是包名一致

接下来就可以在该activity中使用自定义类型的数据了

public class MainActivity extends AppCompatActivity {
    //.....
    public void get(View v) {
        try {
            Toast.makeText(this, iMyName.getStudent().getName(), Toast.LENGTH_SHORT).show();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

}

效果如下

猜你喜欢

转载自blog.csdn.net/zly921112/article/details/53560913