Android,采用AIDL编写接口实现IPC 入门

基本概念

AIDL(Android Interface Definition Language):字面翻译 Android接口定义语言。简而言之,AIDL 是Android实现 IPC(跨进程通信)的开发规则与方法

AIDL官方文档:aidl原理 / 编组与解编 / 默认支持的数据类型 / 开发规则

相关概念

IPC:跨进程通信(interprocess communication)

Binder机制:在Android系统中,个个应用程序都运行在自己的进程中,进程之间一般是无法直接进行数据交换的, 而为了实现跨进程通信,Android给我们提供了Binder机制。进一步了解Binder机制,可以参考 article1,article2

Binder机制的实现就采用了AIDL。简而言之,(初步理解)由于进程A无法直接访问另一个进程B的内存空间,而Android系统可以访问他们的内存空间,所以Android系统就充当了跨进程通信的中介,进程B把自己的方法托付给系统。然后,间接地,进程A(client)就可以访问进程B了

Binder类实现了IBinder接口;bindService--onBind--onServiceConnected就用到了IBinder接口与Binder类

一般情况下一个程序只有一个进程,这个程序的所有组件(四大组件)都在该进程中的主线程中跑。跨进程通信可以算是远程访问,涉及多个进程。本地service默认情况下运行在当前进程的主线程中,远程service运行在另一个进程中。

注意:只有在需要不同应用的客户端通过 IPC 方式访问服务,并且希望在服务中进行多线程处理时,您才有必要使用 AIDL。如果您无需跨不同应用执行并发 IPC,则应通过实现 Binder 来创建接口;或者,如果您想执行 IPC,但需要处理多线程,请使用 Messenger 来实现接口。无论如何,在实现 AIDL 之前,请您务必理解绑定服务

初次体验AIDL

IDE:Android studio

1.在serverAPP中编写aidl文件,在src/main/aidl/com.clc.app5包下现建 IRemoteService.aidl(编写规则参照官网)

2.build项目,自动生成接口文件 IRemoteService.java,可在 build/generator/.../com.clc.app5包下查看

3.在service中实现接口,并将接口对象通过onBind()方法返回给客户端clientAPP的onServiceConnected()方法

4.在客户端clientAPP中获取到接口对象,调用其方法

service和客户端不在一个app中,否则用不着aidl

初步理解
    activity与service的通信,归根结底是通过调用IRemoteService.Stub中的方法实现的
    service--data-->activity:设置方法的返回值,在service中返回对象,在activity中获取
    activity--data-->service:设置方法的参数,在activity调用时传入,在service中获取

当某个组件(client)调用bindService方法绑定同一个APP中的service时,client自然可以调用service的onBind方法返回的对象。当client和service处在两个APP时,还想实现这种处理,就要用AIDL编写两个APP都认可的接口。

例1:service--data-->activity

在serverAPP中

package com.clc.app5;

import android.os.Parcel;
import android.os.Parcelable;

public class City implements Parcelable {

    public int cityId;
    public String cityName;

    public City() {
    }

    public City(int cityId, String cityName) {
        this.cityId = cityId;
        this.cityName = cityName;
    }

    /*
        解包
         */
    protected City(Parcel in) {
        cityId = in.readInt();
        cityName = in.readString();

    }

    public static final Creator CREATOR = new Creator() {
        @Override
        public City createFromParcel(Parcel in) {
            return new City(in);
        }

        @Override
        public City[] newArray(int size) {
            return new City[size];
        }
    };

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

    /*
    打包
     */
    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeInt(cityId);
        parcel.writeString(cityName);
    }
}
================================
『src/main/aidl/com.clc.aidl.City.aidl』

// City.aidl
package com.clc.app5;

// Declare any non-default types here with import statements
parcelable City;
=====================================

『src/main.aidl/com.clc.aidl.IRemoteService.aidl』


// IRemoteService.aidl
package com.clc.app5;

import com.clc.app5.City;

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

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

    City getCity();
}
=================================
package com.clc.app5;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class MyService1 extends Service {
    public MyService1() {
    }

    IRemoteService.Stub binder = new IRemoteService.Stub(){


        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }
        
        //service--data-->activity
        //就把数据设置成返回值,返回给调用处
        @Override
        public City getCity() throws RemoteException {
            return new City(123,"nanjing");
        }

    };

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

把serverAPP中aidl以及相关的实体类连同包一起复制到clientAPP中

然后在clientAPP中调用:

=========================================
『MainActivity』
        
        //执行一次bindService后,再执行bindService就不会触发该方法;除非unbind后再次bind
        //一次bind,对应一次执行,也就是一次性操作
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            IRemoteService iRemoteService = IRemoteService.Stub.asInterface(iBinder);
            try {
                City city = iRemoteService.getCity();
                Log.d(TAG, "onServiceConnected: "+city.cityId+city.cityName);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

例2:activity--data-->service

// IRemoteService.aidl
package com.clc.app5;

import com.clc.app5.City;

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

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

    //AIDL支持的数据类型默认in,其他显示加上in/out/inout
    void setCity(in City city);
}

================


package com.clc.app5;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class MyService1 extends Service {
    public static final String TAG = "MyService1";
    public MyService1() {
    }

    /*
    初步理解
    activity与service的通信,归根结底是通过调用IRemoteService.Stub中的方法实现的
    service--data-->activity:设置方法的返回值,在service中返回对象,在activity中获取
    activity--data-->service:设置方法的参数,在activity调用时传入,在service中获取
     */
    IRemoteService.Stub binder = new IRemoteService.Stub(){


        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        //activity--data-->service
        //就把数据设置成参数,在调用处传入数据
        @Override
        public void setCity(City city) throws RemoteException {

            Log.d(TAG, "setCity: "+city.cityId+city.cityName);
        }


    };

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}
=========================
『MainActivity』

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            IRemoteService iRemoteService = IRemoteService.Stub.asInterface(iBinder);
            try {
                iRemoteService.setCity(new City(12334,"nanjing"));
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

例3:传递数据包 bundle

// IRemoteService.aidl
package com.clc.app5;

import android.os.Bundle;

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

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

    //AIDL支持的数据类型默认in,其他显示加上in/out/inout
    void setBundle(in Bundle bundle);
}



=====================================	

『service的new IRemoteService.Stub(){}中』


	@Override
        public void setBundle(Bundle bundle) throws RemoteException {
            /*
            如果您的 AIDL 接口包含接收软件包作为参数(预计包含 Parcelable 类型)的方法,则在尝试从软件包读取之前,
            请务必通过调用 Bundle.setClassLoader(ClassLoader) 设置软件包的类加载器。
            否则,即使您在应用中正确定义 Parcelable 类型,也会遇到 ClassNotFoundException。
             */
            bundle.setClassLoader(getClass().getClassLoader());
            City city = bundle.getParcelable("city");
            Log.d(TAG, "setBundle: "+city.cityId+city.cityName);
        }

============================

『MainActivity』

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            IRemoteService iRemoteService = IRemoteService.Stub.asInterface(iBinder);

            Bundle bundle = new Bundle();
            bundle.putParcelable("city",new City(1233,"nanjingggggggggggggggggggggggggggggggg"));
            try {
                iRemoteService.setBundle(bundle);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

 

 

你可能感兴趣的