Android IPC之AIDL浅谈

本文详细介绍了Android Interface Definition Language (AIDL) 的使用方法。从官方文档出发,讲解了AIDL支持的数据类型,并通过创建一个服务端应用和客户端应用演示了AIDL的使用流程。最后总结了使用AIDL的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    接触Android久的朋友,就会在面试或者实际开发中遇到AIDL,那么今天我们就来看看AIDL。AIDL是用于进程间通信的。

 一、官方描述

       1.1 文档说明

       AIDL-Android Interface Definition Language,android接口定义语言,它与你可能已经使用过的其他接口定义语言很类似,它允许你定义接口规则,在客户端和服务器约定为了相互之间能使用IPC(进程间通信)通信。在Android中,正常情况下,一个进程无法访问另外一个进程的内存。所以,它们需要将对象分解成操作系统可以识别的原始的类型,这些有序的对象可以穿过边界为你。代码做编组,是比较繁琐的,但是如果你使用AIDL,那么Android将会自己处理。

PS:1. 使用AIDL的条件是,允许不同的客户端应用访问你的服务,并且在服务端还需要处理多进程。(多客户端、多线程、IPC)

      2. 如果你不需要并发处理不同应用的IPC,你应当创建一个接口实现Binder。

      3. 如果你只执行IPC,不需要处理对线程,那么使用Messenger实现一个接口。有关Messenger,可以参考 Android IPC之Messenger浅谈

      补:在实现AIDL时,要先绑定一个服务。

     1.2  数据类型。

AIDL支持的数据类型有以下几种,

    1.支持Java原始数据类型。支持基本数据类型有byte,int,long,float,double,boolean,char,注意没有‘short’。
    2.支持String和CharSequence。
    3.支持java.util.List和java.util.Map。集合中项的允许数据类型包括Java原始类型、String、CharSequence或是android.os.Parcelable。无需为List和Map提供import语句,但需 要为Parcelable提供import语句。
    4.支持传递实现了Android.os.Parcelable接口的复杂类型,同样在引用这些类型时也需要import语句。Parcelable 是Android提供的实现序列化方式。

二、创建AIDL。

为了模拟使用AIDL,需要创建两个应用,一个是服务端,一个客户端。打算实现一个简单的加法计算功能。首先看看服务端的具体实现,

2.1 服务端的具体实现。

1. 打开Android Studio,创建一个Moudle,命名为AidlServer,然后创建一个CalculateAidl的AIDL文件,具体代码如下;

package xinxing.aidltest;


interface CalculateAidl {
  int add(int num1,int num2);
}
代码比较简单,就是定义了一个接口,里面有一个方法。

2. 需要创建一个继承Service的服务,这个服务是用来实现AIDL接口以及提供远程调用,具体看实现,

package xinxing.aidltest;

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

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

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

    private IBinder binder= new CalculateAidl.Stub(){
        @Override
        public int add(int num1, int num2) throws RemoteException {
            int result=num1+num2;
            return result;
        }
    };
}
代码比较少、也简单,了解Service的应该很容易看懂。还是再次解释下,在该Service中通过stub(存根) 返回了IBinder对象,并且在该过程中实现了AIDL接口的方法。

至此,服务端的开发就结束了!就是这么简约!吐舌头

2.2 客户端实现。

1. 打开Android Studio,创建一个Moudle,命名为AidlClient,接着把服务端的AIDL文件直接复制拷贝到该项目中(客户端和服务端的AIDL文件以及包名称一定要一样)。

2. 实现布局编码。此处就不罗列了!

3. 主要功能。在调用AIDL接口时,我们首先需要绑定一个远程服务,

   /**
     * 绑定服务
     */
    private void bindService() {
        //先检查服务端应用是否安装
        if (AppUtils.checkPackage(MainActivity.this, "xinxing.aidltest")) {
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("xinxing.aidltest", "xinxing.aidltest.CalculateService"));
            bindService(intent, conn, Context.BIND_AUTO_CREATE);

        } else {
            isBindSuccess=false;
            Toast.makeText(MainActivity.this, "第三方应用可能未安装成功,请检查后,再试!", Toast.LENGTH_LONG).show();
        }
    }
绑定远程服务,首先判断服务应用是否安装,安装了,才去绑定服务,没有安装,提示‘未安装’。

 //远程连接
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            calculateAidl = CalculateAidl.Stub.asInterface(service);
            isBindSuccess=true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            calculateAidl = null;
            isBindSuccess=false;
        }
    };
远程连接成功,通过IBinder对象获取到AIDL实例,下面就是如何调用接口了,

  if (!isBindSuccess) {
            Toast.makeText(MainActivity.this, "第三方应用可能未安装成功,请检查后,再试!", Toast.LENGTH_LONG).show();
            return;
        }
        if (TextUtils.isEmpty(etNum1.getText().toString())) {
            Toast.makeText(MainActivity.this, "请输入第一个数字", Toast.LENGTH_LONG).show();
            return;
        }
        int num1 = Integer.parseInt(etNum1.getText().toString());
        if (TextUtils.isEmpty(etNum2.getText().toString())) {
            Toast.makeText(MainActivity.this, "请输入第二个数字", Toast.LENGTH_LONG).show();
            return;
        }
        int num2 = Integer.parseInt(etNum2.getText().toString());
        try {
            String result = String.valueOf(calculateAidl.add(num1, num2));
            tvResult.setText(result);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
代码比较简单,就不多说了!至此,客户端的代码也ok 了!

这是当服务端应用没有安装时,点击计算按钮的效果截图,

这是当服务端应用已经安装,点击计算按钮的效果截图,

下面展示MainActivity的全部代码,

package xinxing.aidlclient;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import xinxing.aidltest.CalculateAidl;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText etNum1;
    private EditText etNum2;
    private TextView tvResult;
    private Button btn;
    private CalculateAidl calculateAidl;//aidl对象
    private boolean  isBindSuccess=false;//是否绑定成功
    //远程连接
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            calculateAidl = CalculateAidl.Stub.asInterface(service);
            isBindSuccess=true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            calculateAidl = null;
            isBindSuccess=false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        etNum1 = (EditText) findViewById(R.id.et_num1);
        etNum2 = (EditText) findViewById(R.id.et_num2);
        tvResult = (TextView) findViewById(R.id.tv_result);
        btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(this);
        bindService();
    }


    @Override
    public void onClick(View v) {
        if (!isBindSuccess) {
            Toast.makeText(MainActivity.this, "第三方应用可能未安装成功,请检查后,再试!", Toast.LENGTH_LONG).show();
            return;
        }
        if (TextUtils.isEmpty(etNum1.getText().toString())) {
            Toast.makeText(MainActivity.this, "请输入第一个数字", Toast.LENGTH_LONG).show();
            return;
        }
        int num1 = Integer.parseInt(etNum1.getText().toString());
        if (TextUtils.isEmpty(etNum2.getText().toString())) {
            Toast.makeText(MainActivity.this, "请输入第二个数字", Toast.LENGTH_LONG).show();
            return;
        }
        int num2 = Integer.parseInt(etNum2.getText().toString());
        try {
            String result = String.valueOf(calculateAidl.add(num1, num2));
            tvResult.setText(result);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    /**
     * 绑定服务
     */
    private void bindService() {
        //先检查服务端应用是否安装
        if (AppUtils.checkPackage(MainActivity.this, "xinxing.aidltest")) {
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("xinxing.aidltest", "xinxing.aidltest.CalculateService"));
            bindService(intent, conn, Context.BIND_AUTO_CREATE);

        } else {
            isBindSuccess=false;
            Toast.makeText(MainActivity.this, "第三方应用可能未安装成功,请检查后,再试!", Toast.LENGTH_LONG).show();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (isBindSuccess) {
            unbindService(conn);
        }
    }
}
记得在Activity销毁的时候,解除绑定。

三、总结。

使用AIDL,首先需要定义接口以及接口使用到的数据类型,如果是比复杂的数据类型,需要自己通过Parcelable去实现序列化。继承一个Service实现AIDL接口定义的方法。调用该AIDL方法是,最好能加入判断(被调用的应用是否安装的判断)。

1. 使用AIDL的情况是多线程、 多应用 、IPC。

2. 使用AIDL时,客户端和服务端的AIDL文件以及包名都要一样。

推荐一篇IPC文章, Android IPC之Messenger浅谈



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值