项目链接:https://github.com/liaozhoubei/AIDLService

AIDL:Android Interface Definition Language,即Android接口定义语言,这是一种用于Android的跨进程通信(IPC)的工具。
为什么有AIDL呢?这是因为在android中一个进程不允许直接访问另一个进程的内存。
进程是一个应用在手机上执行的过程,这是一个动态的概念,一个app的主进程可以从这个app打开算起,然后直接退出app,这时就算是一个进程的结束。
在android中允许有多进程,因此多进程通信可以在自己的应用中进行通信,也可以在不同应用中通信,而这便是AIDL的使用方向。
但是AIDL有个缺点,那就是比较耗资源,如非必要,就不适用AIDL的为好

AIDL的使用方法

我们知道了AIDL是用来干什么的,那么我们就开始学习如何使用AIDL吧!

我们先建立一个AIDLService项目,这个项目用来模拟远程服务端口的,即我们想通过AIDL调用这个项目中的方法,这就是跨进程通信。

由于只是一个小Demo,所以并没有做太复杂的东西,我们只想通过AIDLService这个进程进行一次基本数据类型的传递,即进行简单的计算,然后将计算结果传回去客户端中。
其次,我们还想通过AIDLService将一个Object对象传给客户端。

那么我们就开始吧。

AIDLService服务端: 创建一个AIDL文件

首先必须要有一个AIDL接口文件,即后缀名为aidl的文件,在这里我们是IService.aidl,代码如下

interface IService {    // 传入两个正整数,返回他们的和    int add(int num1, int num2);    // 传入一个Person对象,返回person集合    List addPerson(in Person p);}

看上去是不是很熟悉,没错,这其实就是一个interface接口而已,区别在于它并没有public或者private等修饰符。
其中addPerson(in Person p)中我们看到有个in Person p,这个in是什么呢?简单的说表示这个Person是从外面传进来的(可以自行搜索其中的意思)。

除此之外还需要创建一个Person.aidl,传递序列号之后的Person对象,代码很简单,如下:

parcelable Person;

就这么一行代码。

AIDLService服务端: 创建一个RemoteService远程服务

RemoteService远程服务中将实现IService.aidl中的两个方法,让后通过IBinder传出(IBinder可以让外界调用服务中的方法)。具体代码如下:

public class RemoteService extends Service {    public final String TAG = this.getClass().getSimpleName();    private ArrayList persons;    public RemoteService() {    }    @Nullable    @Override    public IBinder onBind(Intent intent) {        persons = new ArrayList<>();        return iBinder;    }    private IBinder iBinder = new IService.Stub() {        @Override        public int add(int num1, int num2) throws RemoteException {            return num1 + num2;        }        @Override        public List addPerson(Person p) throws RemoteException {            persons.add(p);            return persons;        }    };}

当然,我们不要忘记建立Person.java,而且要对这个类实现序列号,因为Object必须实现序列号才能同传输,代码如下:

public class Person implements Parcelable {    private String name;    private int age;    public Person(String name, int age) {        this.name = name;        this.age = age;    }    protected Person(Parcel in) {        // 从序列号中取出数据,要按照writeToParcel()写入的顺序一样取出        this.name = in.readString();        this.age = in.readInt();    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString() {        return "Person{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }    @Override    public int describeContents() {        return 0;    }    /**     * 将数据写入序列化中     * @param dest     * @param flags     */    @Override    public void writeToParcel(Parcel dest, int flags) {        // 写入时的顺序决定取出数据时的顺序        dest.writeString(name);        dest.writeInt(age);    }    /**     * 必须实现的方法,写法基本固定     */    public static final Creator CREATOR = new Creator() {        /**         * 从序列化中取出一个个的字段         * @param in         * @return         */        @Override        public Person createFromParcel(Parcel in) {            return new Person(in);        }        @Override        public Person[] newArray(int size) {            return new Person[size];        }    };}

OK,这样我们的AIDLService服务端就已经完成了,剩下的就是使用客户端调用了。

AIDLClient客户端

客户端用来调用AIDLService中的两个方法,那么如何调用呢?
首先必须要创建AIDLClient客户端。

然后我们直接把AIDLService当中的Person.aidl和IService.aidl两个文件拷贝到,需要注意的是这里两个文件所在的包名必须与在AIDLService时的包名保持一致。
还需要把Person.java拷贝过来,包名也需要保持一致。

AIDLClient客户端需要一个简单的界面,activity_main.xml代码如下:

                                                    

非常简单,这里就不做解释了。

AIDLClient客户端:调用远程服务

MainActivity中的布局写好了,那么我们就开始进行远程吧。方法其实就使用本地服务基本一样。代码如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private EditText num1;    private EditText num2;    private EditText result;    private EditText name;    private EditText age;    private EditText getPerson;    private Button btn_1;    private Button btn_2;    IService iService;    /**     * 创建ServiceConnection与服务进行链接     */    private ServiceConnection conn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            iService = IService.Stub.asInterface(service);        }        @Override        public void onServiceDisconnected(ComponentName name) {            iService = null;        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();        bindService();    }    private void initView() {        num1 = (EditText) findViewById(R.id.num1);        num2 = (EditText) findViewById(R.id.num2);        result = (EditText) findViewById(R.id.result);        btn_1 = (Button) findViewById(R.id.btn_addNumber);        btn_2 = (Button) findViewById(R.id.btn_addPerson);        name = (EditText) findViewById(R.id.name);        age = (EditText) findViewById(R.id.age);        getPerson = (EditText) findViewById(R.id.getPerson);        btn_1.setOnClickListener(this);        btn_2.setOnClickListener(this);    }    /**     * 与远程服务进行绑定     */    private void bindService() {        Intent intent = new Intent();        // 传入AIDL的包名,以及调用远程服务的全类名        intent.setComponent(new ComponentName("com.example.aidlservice", "com.example.aidlservice.RemoteService"));        bindService(intent, conn, Context.BIND_AUTO_CREATE);    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.btn_addNumber:                int num1 = Integer.parseInt(this.num1.getText().toString());                int num2 = Integer.parseInt(this.num2.getText().toString());                try {                    int num = iService.add(num1, num2);                    result.setText(num + "");                    Toast.makeText(getApplicationContext(), num + "来到了", Toast.LENGTH_LONG).show();                } catch (RemoteException e) {                    e.printStackTrace();                }                break;            case R.id.btn_addPerson:                String p1 = name.getText().toString();                int num3 = Integer.parseInt(age.getText().toString());                Person person = new Person(p1, num3);                try {                    ArrayList persons = (ArrayList) iService.addPerson(person);                    Toast.makeText(getApplicationContext(), persons.toString(), Toast.LENGTH_SHORT).show();                } catch (RemoteException e) {                    e.printStackTrace();                }                break;        }    }}

在这里,我们看到基本与调用本地的服务的方法没多大区别,只是在使用bindService()方法时,我们要设置包名,即设置我们要访问的服务的信息,

intent.setComponent(new ComponentName("com.example.aidlservice", "com.example.aidlservice.RemoteService"));

总结

AIDL的使用并不难,而且在调用的时候也就象使用普通的服务一样,区别只在双方都必须有aidl文件,其中表明能够被调用的方法而已。
下面总结一下aidl多进程通信的使用步骤

  • 首先服务都创建aidl接口文件,这个接口文件表示里面的方法能被外部调用。同时要注意的是如果有Object对象传输,必须实现Parcelable接口。
  • 创建一个Service,通过IBinder实现aidl接口中的方法,然后再onBind()中返回这个IBinder.
  • 在客户端复制服务端的aidl文件,同时保持包名一致,如果有Object对象,也一样要复制。
  • 直接通过bindService()方法绑定服务,调用IBinder中的方法。

更多相关文章

  1. Android Binder机制(三) ServiceManager守护进程
  2. Android 中文设置成粗体的方法
  3. 极光推送(守护进程)
  4. Bitmap和Drawable相互转换方法
  5. android onSaveInstanceState方法 横坚屏切换
  6. Android P 以及之后版本不支持同时从多个进程使用具有相同数据目
  7. Android Studio 编译提示 aapt.exe finished with non-zero exit
  8. android中处理json最佳方法

随机推荐

  1. 下载编译android kernel
  2. Android studio 编译时出现Process 'comm
  3. Android 7.1 Launcher3 支持按键操作显示
  4. android底部菜单栏的实现和百度地图API的
  5. Robolectric使用(四)自定义
  6. Android下的一些调试手段(含kernel调试办
  7. android ViewPager,ViewFlipper,ViewFlow
  8. Android(安卓)Java 获取剪切板的内容,MD5
  9. Android视频处理 --处理视频第一帧缩略图
  10. Android——eclipse共享library以及导出j