安卓中AIDL的使用

  • AIDL简介

    AIDL,全称是Android Interface Define Language,即安卓接口定义语言,可以实现安卓设备中进程之间的通信(Inter Process Communication, IPC)。

  • AIDL的使用

    假设有如下场景,需要计算a+b的值,在客户端中获取a和b的值,然后传递给服务端,服务端进行a+b的计算,并将计算结果返回给客户端。
    这里的客户端和服务端均是指安卓设备中的应用,由于每一个应用对应一个进程,由此可以模拟安卓系统中通过AIDL进行进程之间的通信。
    AIDL的具体使用步骤如下:

1) 创建Project,命名为AIDLDemo

2) 将android studio自动生成的app module作为服务端应用,在此Procject中再新建一个module作为客户端应用,命名为aidlclient。

3) 在两个module中均新建一个与java文件夹同级的文件夹,命名为aidl,用于存放aidl文件,然后再分别在aidl文件夹下新建包,注意,两个module的新建包包名必须相同,然后在两个包中分别新建一个同名的aidl文件。项目的最终结构如下图:
这里写图片描述

4) 编辑AIDL文件
在服务端和客户端的AIDL文件中均编写add(int num1, int num2)方法,无需具体实现

// IMyAidlInterface.aidl
package com.zheero.aidldemo;

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

interface IMyAidlInterface {
    int add(int num1, int num2);
}

5) 点击同步按钮,会自动生成一个与aidl对应的java文件,其实是一个接口类
这里写图片描述
在该文件中,可以找到一个proxy类,这是一个代理类,运行在客户端中,其实客户端与服务端没有进行直接通信,客户端调用的add方法是proxy中的,然后代理类proxy再与服务端进行通信,将服务端返回的结果返回给客户端。

proxy类的简单解析如下

//代理类,运行在客户端中
        private static class Proxy implements com.zheero.aidldemo.IMyAidlInterface {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }
            //客户端调用此方法,传递进来num1和num2两个参数
            @Override
            public int add(int num1, int num2) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    //向_data中写入两个参数num1和num2
                    _data.writeInt(num1);
                    _data.writeInt(num2);
                    //通过transact方法向服务端传递参数,并调用了方法,返回的结果写入_reply中
                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                    _reply.readException();
                    //读取返回的结果
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

在该文件中,还有一个Stub类,运行在服务端中,其中的onTransact方法解析如下

//运行在服务端Binder线程池中
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_add: {
                    data.enforceInterface(DESCRIPTOR);
                    //读取客户端传过来的参数
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    //调用add方法对参数进行运算
                    int _result = this.add(_arg0, _arg1);
                    reply.writeNoException();
                    //返回计算结果
                    reply.writeInt(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

6) 在服务端中新建一个类,继承Service,在其中定义一个IBinder类型的变量iBinder,引用上述接口类中的Stub类对象,实现其中的add方法,在Service的onBind方法中,返回iBinder变量。最终代码如下:

public class IRemoteService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //将接口暴露给客户端
        return iBinder;
    }

    private IBinder iBinder = new IMyAidlInterface.Stub(){
        //实现aidl中定义的方法
        @Override
        public int add(int num1, int num2) throws RemoteException {
            return num1 + num2;
        }
    };
}

注意在服务端的Manifast文件中注册该Service,在注册时应设置exported属性为true,保证该Service能被其他应用调用,否则会报
java.lang.SecurityException: Not allowed to bind to service Intent 异常。

<service android:name=".IRemoteService"
            android:exported="true"/>

至此,与配置AIDL有关的工作完成

7) 客户端界面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <EditText
        android:gravity="center|right"
        android:id="@+id/et_num1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="+"
        android:textSize="24sp"
        android:layout_gravity="center"
        android:gravity="right|center"/>
    <EditText
        android:gravity="center|right"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_num2"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="="
        android:textSize="24sp"
        android:layout_gravity="center"
        android:gravity="right|center"/>
    <EditText
        android:gravity="center|right"
        android:editable="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/edit_show_result"
        android:textSize="24sp"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_count"
        android:text="远程计算"
        android:gravity="center"
        android:textSize="24sp" />
</LinearLayout>

8) 客户端MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText et_num1;
    private EditText et_num2;
    private EditText edit_show_result;
    private Button btn_count;
    private int mNum1;
    private int mNum2;
    private int mTotal;
    private IMyAidlInterface iMyAidlInterface;
    private final String TAG = getClass().getSimpleName();
    //绑定服务回调
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //服务绑定成功后调用,参数中的service即是在服务端onBind方法中返回的iBinder,即已实现的接口
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            Log.i(TAG, "onServiceConnected: iMyAidlInterface" + iMyAidlInterface);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            //解除绑定时调用, 清空接口,防止内容溢出
            iMyAidlInterface = null;
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        bindService();
    }

    private void initView(){
        et_num1 = (EditText) findViewById(R.id.et_num1);
        et_num2 = (EditText) findViewById(R.id.et_num2);
        edit_show_result = (EditText) findViewById(R.id.edit_show_result);
        btn_count = (Button) findViewById(R.id.btn_count);
        btn_count.setOnClickListener(this);
    }

    /**
     * 绑定服务
     */
    private void bindService(){
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.zheero.aidldemo"
                , "com.zheero.aidldemo.IRemoteService"));
        boolean isBind = bindService(intent, conn, Context.BIND_AUTO_CREATE);
        Log.i(TAG, "bindService: isBind->"+isBind);
    }

    @Override
    public void onClick(View v) {
        mNum1 = Integer.parseInt(et_num1.getText().toString());
        mNum2 = Integer.parseInt(et_num2.getText().toString());
        try {
            mTotal = iMyAidlInterface.add(mNum1, mNum2);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        edit_show_result.setText(mTotal+"");
    }

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

先启动服务端,再启动客户端,输入参数进行计算

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AIDLAndroid Interface Definition Language)是一种Android特有的IPC(Inter-Process Communication,进程间通信)机制,可以实现跨进程通信。以下是使用AIDL实现跨进程通信的步骤: 1. 定义AIDL接口:在AIDL文件定义接口和方法,这些接口和方法将在不同进程之间进行调用。例如,定义一个接口IStudentManager和一个方法addStudent()。 2. 实现AIDL接口:在Service实现AIDL接口,可以在Service创建一个Binder对象,然后将该对象返回给客户端客户端可以使用这个Binder对象调用Service的方法。 3. 绑定Service:在客户端绑定Service,通过这种方式,客户端可以获取到Service的Binder对象,然后调用Service的方法。 4. 调用方法:在客户端通过Binder对象调用Service的方法,实现跨进程通信。 注意事项: 1. 在使用AIDL时,需要在AndroidManifest.xml文件注册Service。 2. AIDL接口只能使用基本数据类型和Parcelable类型,不支持其他类型。 3. AIDL接口定义的方法必须是线程安全的,因为它们可能在不同进程被调用。 4. AIDL接口定义的方法必须是只读的,不应该修改传入的参数。 5. AIDL接口的方法返回值必须是void或者基本数据类型、String、CharSequence、Parcelable类型。 6. AIDL接口的方法可以抛出RemoteException异常,因为AIDL接口是基于Binder实现的,所以需要处理Binder连接断的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值