AndroidStudio 中 AIDL 使用实战以及采坑总结

什么是 AIDL

AIDL : Android Interface Definition Language,即 Android 接口定义语言。

Android 系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。为了使其他的应用程序也可以访问本应用程序提供的服务,Android 系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样, Android 使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。我们知道4个 Android 应用程序组件中的 3 个(Activity、BroadcastReceiver和ContentProvider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。因此,可以将这种可以跨进程访问的服务称为 AIDL(Android Interface Definition Language)服务。

下面用一个实际 demo 来演示 AIDL 如何进行 RPC 的。

实战演示

服务端
  1. 创建 AIDL 文件,选中要提供的服务类所在的包名,右键 -> New -> AIDL -> AIDL File文件,如图所示新建一个名为 IPerson.aidl 的文件。

在这里插入图片描述
2. 打开 aidl 文件,定义对外暴露的方法;重新编译一下项目,如果成功编译那么会在如下目录中生成一个名为 IPerson 的接口文件 。

在这里插入图片描述
3. 新建一个接口实现类 PersonImpl,让其继承刚刚自动生成的类里面的 IPerson.Stub 抽象类,并实现接口里面的抽象方法。

在这里插入图片描述
4. 新建一个服务类 MyService ,让其继承自 Service,并在 onBind 方法中返回上一步的实现(PersonImpl)的实例。

在这里插入图片描述
5. 在 manifest.xml 文件中给 MyService 服务定义一个 action ,至此服务端代码写完了.
在这里插入图片描述

客户端
  1. 将服务端的 AIDL 文件夹复制一份到客户端的 main 目录下如图所示
    在这里插入图片描述
  2. rebuild project 客户端项目,结束后,应该会生成和服务端一模一样的接口。
  3. 绑定服务,得到服务返回的 Ibinder 对象,强转为接口的类型,并调用接口的方法,去间接调用服务中的方法。
package com.example.demo_aidlclient;

import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import com.xzy.study.aidl.R;

import aidl.xzy.aidl.IPerson;


/**
 * AIDL 客户端
 *
 * @author xzy
 */
public class MainActivity extends Activity {
    private IPerson person;
    private final ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName arg0) {
        }

        // 因为有可能有多个应用同时进行RPC操作,所以同步该方法
        @Override
        public synchronized void onServiceConnected(ComponentName arg0, IBinder binder) {
            // 获得IPerson接口
            person = IPerson.Stub.asInterface(binder);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btn = (Button) findViewById(R.id.button1);
        //客户端中不需要在manifest中配置 RemoteService
        // intent 中的 action 为服务端 AndroidManifest 中服务定义的 aciton 的名称
        Intent intent = new Intent("forServiceAidl");
        // 包名设置为服务端 app 包名
        intent.setPackage("com.xzy.study.aidlserver");
        bindService(intent, conn, Service.BIND_AUTO_CREATE);
        btn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (person != null) {
                    try {
                        // RPC方法调用
                        String name = person.getName();
                        Toast.makeText(MainActivity.this, "远程进程调用成功!值为 : " + name,
                                Toast.LENGTH_LONG).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                        Toast.makeText(MainActivity.this, "远程进程调用失败! ",
                                Toast.LENGTH_LONG).show();
                    }
                }
            }
        });
    }

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

采坑总结

  1. 服务端 aidl 文件目录和客户端必须保持完全一致
  2. 服务端 Service 定义的 action 名称必须和绑定服务时传入的 action 保持一致(客户端也一样)
  3. 服务类只定义在服务端,且需要在 manifest.xml 中进行注册。客户端不需要定义服务类,也不需要注册。
  4. 客户端设置包名的时候,设置的是服务端 app 的包名。这一点需要注意。
 //客户端中不需要在manifest中配置 RemoteService
 // intent 中的 action 为服务端 AndroidManifest 中服务定义的 aciton 的名称
 Intent intent = new Intent("forServiceAidl");
 // 包名设置为服务端 app 包名
 intent.setPackage("com.xzy.study.aidlserver");
 bindService(intent, conn, Service.BIND_AUTO_CREATE);

源码

  1. https://github.com/hgncxzy/Demo-AIDL-Client
  2. https://github.com/hgncxzy/Demo-AIDL-Server

参考文章

  1. https://blog.csdn.net/a981814480/article/details/80310512
  2. https://www.cnblogs.com/cmt/p/14553189.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值