Android笔记三:Android 接口定义语言 (AIDL)--基本用法

来源:互联网 发布:淘宝二手车市场 编辑:程序博客网 时间:2024/04/29 07:29

Android 接口定义语言 (AIDL)–基本用法

IPC是Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信,至两个进程间进行数据交换的过程。

进程概念:一般只一个执行单元,在移动设备上一遍指一个应用或者程序。

线程概念:线程是cpu调度的最小单元,同时线程也是有限的系统资源。

一个进程可以包含多个线程。

可以通过android:process属性指定进程,轻易开启一个进程,没有指定该属性就是默认进程名为包名,例如

android:process=":remote"//进程名为报名加":remote"android:process="com.lynnlee.remote"

这里写图片描述

AIDL 创建绑定服务

默认情况下,AIDL 支持下列数据类型:

基本数据类型(如 int、long、char、boolean 等等,除short);String;CharSequence;List;Map;Parcelable。

List:中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 可选择将 List 用作“通用”类(例如,List)。另一端实际接收的具体类始终是 ArrayList,但生成的方法使用的是 List 接口。

Map:中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 不支持通用 Map(如 Map

步骤:

  • 1.创建 .aidl 文件
    此文件定义带有方法签名的编程接口。保存在托管服务的应用以及任何其他绑定到服务的应用的源代码(src/ 目录)内。
    这里写图片描述

  • 2.实现接口
    Android SDK 工具基于您的 .aidl 文件,使用 Java 编程语言生成一个接口。此接口具有一个名为 Stub 的内部抽象类,用于扩展 Binder 类并实现 AIDL 接口中的方法。您必须扩展 Stub 类并实现方法。

  • 3.向客户端公开该接口
    实现 Service 并重写 onBind() 以返回 Stub 类的实现。

注意:在 AIDL 接口首次发布后对其进行的任何更改都必须保持向后兼容性,以避免中断其他应用对您的服务的使用。 也就是说,因为必须将您的 .aidl 文件复制到其他应用,才能让这些应用访问您的服务的接口,因此您必须保留对原始接口的支持。

1. 创建 .aidl 文件

这里写图片描述

//IRemoteService.aidlpackage com.example.admin.aidlservice;interface IRemoteService {    int add(int num1, int num2);}

不是基本数据类型就需要导包,即使在同一个包下,并且得指定方向。

2. 实现接口

Android SDK 工具会生成一个以 .aidl 文件命名的 .java 接口文件。生成的接口包括一个名为 Stub 的子类,这个子类是其父接口(例如,IRemoteService.Stub)的抽象实现,用于声明 .aidl 文件中的所有方法。

注意:

  • 1.AndroidStudio需要点击编译Sync Project才可生成IRemoteService.java,位置在build–>generated–>source–>aidl–>debug下。

这里写图片描述

  • 2.Stub 还定义了几个帮助程序方法,其中最引人关注的是 asInterface(),该方法带 IBinder(通常便是传递给客户端 onServiceConnected() 回调方法的参数)并返回存根接口实例。

以下是一个使用匿名实例实现名为 RemoteService 的接口

private IRemoteService.Stub mBinder = new IRemoteService.Stub() {        @Override        public int add(int num1, int num2) throws RemoteException {            Log.i(TAG, "远程服务被调用了!num1:" + num1 + ",num2:" + num2);            return num1 + num2;        }    };

mBinder 是 Stub 类的一个实例(一个 Binder),在下一步中,将向客户端公开该实例,以便客户端能与服务进行交互。

3. 向客户端公开该接口

您为服务实现该接口后,就需要向客户端公开该接口,以便客户端进行绑定。 要为您的服务公开该接口,请扩展 Service 并实现 onBind(),以返回一个类实例,这个类实现了生成的 Stub。以下是一个向客户端公开 IRemoteService 示例接口的服务示例。

public class RemoteService extends Service {    private static final String TAG = "lynnlee36";    private IRemoteService.Stub mBinder  = new IRemoteService.Stub() {        @Override        public int add(int num1, int num2) throws RemoteException {            Log.i(TAG, "远程服务被调用了!num1:" + num1 + ",num2:" + num2);            return num1 + num2;        }    };    @Nullable    @Override    public IBinder onBind(Intent intent) {        return mBinder ;    }}

调用 IPC 方法

当客户端(如 Activity)调用 bindService() 以连接此服务时,客户端的 onServiceConnected() 回调会接收服务的 onBind() 方法返回的 mBinder 实例。

客户端还必须具有对 interface 类的访问权限,因此如果客户端和服务在不同的应用内,则客户端的应用 src/ 目录内必须包含 .aidl 文件的副本,拷贝aidl至client端,必须保证报名一致。
这里写图片描述

当客户端在 onServiceConnected() 回调中收到 IBinder 时,它必须调用 IRemoteService.Stub.asInterface(service) 以将返回的参数转换成 IRemoteService类型。例如:

public class MainActivity extends AppCompatActivity {    private static final String TAG = "lynnlee36";    private ServiceConnection conn = new ServiceConnection() {        private IRemoteService iRemoteService;        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            iRemoteService = IRemoteService.Stub.asInterface(service);            try {                int result = iRemoteService.add(5, 4);                Log.i(TAG, "调用远程服务,结果是:" + result);            } catch (RemoteException e) {                e.printStackTrace();                Log.i(TAG, "执行失败!");            }        }        @Override        public void onServiceDisconnected(ComponentName name) {            iRemoteService = null;        }    };    private Button button;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button = (Button) findViewById(R.id.bind_service);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent intent = new Intent();                intent.setComponent(new ComponentName("com.example.admin.aidlservice", "com.example.admin.aidlservice.RemoteService"));                bindService(intent, conn, Context.BIND_AUTO_CREATE);            }        });    }}

注:

  • 1.Android5.0之后不能使用隐士意图绑定服务了。
  • 2.服务需要android:exported,不然会报错。
    这里写图片描述
<service android:name=".RemoteService"            android:exported="true"/>

运行结果:
这里写图片描述