0.什么是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)服务。

 

下面将通过一个示例来说明两个APP之间的AIDL通信。

 

1.工程环境准备

1)通过Android Studio 首先创建一个项目  New Project ->Empty Activity,Name:AIDLDemo, Pakcage:com.android.myservice ,用作Server

android 12开启网络adb端口 android sooner single adb interface_binder

 

2)在项目中再创建一个Module,用来做Client, 在项目文件上 右键 ->New-> Module -> Phone & Tablet Module, 名称填client  -> Empty Activity

android 12开启网络adb端口 android sooner single adb interface_binder_02

3)这样Server和Client的两个环境就准备好了

android 12开启网络adb端口 android sooner single adb interface_hwbinder_03

接下来开始填代码

 

 

2.服务端设计

2.1 创建一个AIDL 文件 IMyService

在服务的文件夹app 中,执行下面的步骤:

右键 -> New -> AIDL->AIDL File, 名称为IMyService

android 12开启网络adb端口 android sooner single adb interface_android 12开启网络adb端口_04

AIDL创建完成

android 12开启网络adb端口 android sooner single adb interface_android 12开启网络adb端口_05

填入一个add的函数,我们用来做加法计算:

Code:

// IMyService.aidl
package com.android.myservice;

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

interface IMyService {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    int add(int num1, int num2);
}

选择 Build -> Make Module "app",会把AIDL进行编译,会自动生成IMyService 这个服务接口,其中实现了stub、proxy的class,以及TRANSACTION的code,用来通信处理

android 12开启网络adb端口 android sooner single adb interface_Android Q_06

2.2 服务实现

在Framework层我们还可以使用addService进行服务注册,但是在应用层,我们不具备相应的权限,只能通过集成Service,开放Service,让Client进行bind。

在JAVA->com.android.myservice 上新建一个Java Class---MyService

android 12开启网络adb端口 android sooner single adb interface_hwbinder_07

package com.android.myservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class MyService extends Service {
static final String TAG = "MyTestService";
//服务实体
    IMyService.Stub mStub = new IMyService.Stub() {

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public int add(int num1, int num2) throws RemoteException {
            Log.d(TAG,"add");
            //服务的接口实现,这里做一个加法运算
            return num1 + num2;
        }
    };
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG,"onBind");
        return mStub;//通过ServiceConnection在activity中拿到MyService
    }
}

2.3 AndroidManifest.xml配置

在AndroidManifest.xml中配上Service的信息,其中enable:ture设置可用,exported:ture对外暴露, 这样其他的Activity才能访问。

<service android:name=".MyService"
    android:enabled="true"
    android:exported="true">
    <!--enable:ture设置可用
       exported:ture对外暴露 -->
    <intent-filter>
       <action android:name="com.android.myservice.myservice"/>
    </intent-filter>
</service>

执行编译,服务端准备完成,编译一个APK进入手机\模拟器

 

3.Client端设计

3.1 AIDL拷贝

把服务端的AIDL以及包目录完整的拷贝到client的mian目录下,让Client和Server的服务对象对等。

android 12开启网络adb端口 android sooner single adb interface_Android10.0_08

接着执行编译 Build-> Make Module "Client",对应的IMyService.java也在client中编译出来

android 12开启网络adb端口 android sooner single adb interface_hwbinder_09

3.2 Client的UI实现

在layout->activity_main.xml 中添加相应的控件,效果如下:

android 12开启网络adb端口 android sooner single adb interface_android 12开启网络adb端口_10

布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/toAdd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="计算"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/result" />

    <Button
        android:id="@+id/bindbtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="绑定服务"
        app:layout_constraintStart_toStartOf="@+id/toAdd"
        app:layout_constraintTop_toBottomOf="@+id/toAdd" />

    <Button
        android:id="@+id/unbindbtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="解除绑定"
        app:layout_constraintStart_toStartOf="@+id/bindbtn"
        app:layout_constraintTop_toBottomOf="@+id/bindbtn" />

    <EditText
        android:id="@+id/num1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#ececec"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/num2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#ececec"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/add" />

    <EditText
        android:id="@+id/result"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#eceaea"
        android:inputType="none"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/value" />

    <TextView
        android:id="@+id/add"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="+"
        android:textSize="25sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/num1" />

    <TextView
        android:id="@+id/value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="1dp"
        android:text="="
        android:textSize="25sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/num2" />

</androidx.constraintlayout.widget.ConstraintLayout>

3.3 Client服务绑定和功能实现

通过bindService进行服务的绑定,unbindService 进行服务的解绑

package com.android.client;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.DialogInterface;
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.widget.Button;
import android.widget.EditText;

import com.android.myservice.IMyService;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
       static final String TAG = "AIDLClient";
    IMyService myService;
    private EditText num1;
    private EditText num2;
    private EditText result;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate ");
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        num1 = (EditText) findViewById(R.id.num1);
        num2 = (EditText) findViewById(R.id.num2);
        result = (EditText) findViewById(R.id.result);

        Button toAdd = (Button) findViewById(R.id.toAdd);
        Button bindbtn = (Button) findViewById(R.id.bindbtn);
        Button unbindbtn = (Button) findViewById(R.id.unbindbtn);
        toAdd.setOnClickListener(this);
        bindbtn.setOnClickListener(this);
        unbindbtn.setOnClickListener(this);
    }

    private ServiceConnection connection = new ServiceConnection() {
        //绑定上服务的时候
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            //接受到了远程的服务
            Log.d(TAG, "onServiceConnected: ");
            myService = IMyService.Stub.asInterface(service);
        }

        // 当服务断开的时候调用
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.d(TAG, "onServiceDisconnected: ");
            //回收资源
            myService = null;

        }
    };

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bindbtn://绑定服务
                Log.d(TAG, "start to bindMyServce");
                bindMyService();
                break;
            case R.id.unbindbtn://解除绑定
                Log.d(TAG, "start to unbindMyServce");
                unbindMyService();
                break;
            case R.id.toAdd://计算数据
                int number1 = Integer.valueOf(num1.getText().toString());
                int number2 = Integer.valueOf(num2.getText().toString());
                try {
                    Log.d(TAG, "start to add");
                    int valueRes = myService.add(number1, number2);
                    result.setText(valueRes + "");
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }
    }

    private void bindMyService() {
        Intent intent = new Intent();
        intent.setAction("com.android.myservice.myservice");
        intent.setPackage("com.android.myservice"); // server's package name
        bindService(intent, connection, BIND_AUTO_CREATE);
        new AlertDialog.Builder(this)
                .setTitle("Tips")
                .setMessage("绑定成功!")
                .setPositiveButton("确定",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                                int whichButton) {

                            }
                        }).show();
        Log.d("AIDLClient", "bindMyService: bind on end");
    }

    private void unbindMyService() {
        unbindService(connection);
        new AlertDialog.Builder(this)
                .setTitle("Tips")
                .setMessage("解除绑定成功!")
                .setPositiveButton("确定",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                                int whichButton) {

                            }
                        }).show();
        Log.d("AIDLClient", "unbindMyService: unbind on end");
    }
}

执行编译,生成client.apk,在手机\模拟器中展示

 

4.测试:

点击“绑定服务”,成功后弹出“绑定成功”:

log:
   Client:

03-21 19:32:49.986 30794 30794 D AIDLClient: start to bindMyServce
03-21 19:32:50.023 30794 30794 D AIDLClient: bindMyService: bind on end
03-21 19:32:50.044 30794 30794 D AIDLClient: onServiceConnected:
03-21 19:32:57.062 30794 30794 D AIDLClient: start to add

Server:

03-21 19:32:49.996 31091 31091 D MyTestService: onCreate
03-21 19:32:49.997 31091 31091 D MyTestService: onBind

android 12开启网络adb端口 android sooner single adb interface_binder_11

在输入框分别输入1,2, 点击计算,执行“1+2”,结果为3,从服务端返回成功

log:
Client:

03-21 19:32:57.062 30794 30794 D AIDLClient: start to add

Server:

03-21 19:32:57.063 31091 31160 D MyTestService: add

android 12开启网络adb端口 android sooner single adb interface_Android Q_12

点击“解除绑定”,成功后弹出“解除绑定成功”:

log:
Client:

03-21 19:35:57.109 30794 30794 I AIDLClient: start to unbindMyServce
03-21 19:35:57.147 30794 30794 D AIDLClient: unbindMyService: unbind on end

android 12开启网络adb端口 android sooner single adb interface_android 12开启网络adb端口_13

下一节专门来讲一讲AIDL的原理

android 12开启网络adb端口 android sooner single adb interface_binder_14