我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android:AIDL实战详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android:AIDL实战详解

AIDL:Android Interface Definition Language

AIDL是为了实现进程间通信而设计的Android接口语言

Android进程间通信有多种方式,Binder机制是其中最常见的一种

AIDL的本质就是基于对Binder的运用从而实现进程间通信

这篇博文从实战出发,用一个尽可能精简的Demo,实现两个App(也是两个进程:服务端mainapp、客户端otherapp)通过AIDL的跨进程通信

废话不多说,开撸!

一.创建两个App

按照下列步骤先创建两个App:

(1).新建一个开发文件夹(本Demo中命名为aidl-test)

(2).使用AndroidStudio在aidl-test文件夹下创建第一个Empty Activity的空App:mainapp

为了后续方便起见

创建完成后,把Studio默认创建的MainActivity.java名字改一下,改成MainAppActivty.java

(3).创建第二个Empty Activity的空App:otherapp

 

两个空App创建完成了:

二.在mainapp中创建一个Service

上一节中新建了两个空App:mainappotherapp

现在就先在mainapp中实现一个service

使用方便又快捷的studio创建MainAppService.java

 

可以看到新建的MainAppService会自动实现一个onBind(Intent intent)方法,这个方法后续我会在其中进行代码实现,它需要在其他进程连接到Service时,返回一个继承了android.os.Binder的对象

先在 MainAppActivity MainAppService 中添加一些必要的生命周期函数代码
再在 MainAppService 中添加:
onBind(Intent intent):被客户端绑定时执行
onUnbind(Intent intent):被客户端解绑时执行

com/android/mainapp/MainAppActivity.java

package com.android.mainapp;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.os.Bundle;import android.util.Log;public class MainAppActivity extends AppCompatActivity {    private String TAG = "AIDL-MainAppActivity";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.v(TAG, "onCreate()");        setContentView(R.layout.activity_main);    }    @Override    protected void onDestroy() {        super.onDestroy();        Log.v(TAG, "onDestroy()");    }}

com/android/mainapp/MainAppService.java 

package com.android.mainapp;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.util.Log;public class MainAppService extends Service {    private String TAG = "AIDL-MainAppService";    public MainAppService() {    }    @Override    public void onCreate() {        super.onCreate();    }    @Override    public void onStart(Intent intent, int startId) {        Log.v(TAG, "onStart()");    }    @Override    public IBinder onBind(Intent intent) {        // TODO: Return the communication channel to the service.        throw new UnsupportedOperationException("Not yet implemented");    }    @Override    public boolean onUnbind(Intent intent) {        Log.v(TAG, "onUnbind()");        return true;    }    @Override    public void onDestroy() {        super.onDestroy();        Log.v(TAG, "onDestroy()");    }}

三.mainapp中实现AIDL

依然使用方便又快捷的AndroidStudio在mainapp的main目录下创建一个名为IAppAidlInterface.aidl 的AIDL文件

 

AndroidStudio创建 IAppAidlInterface.aidl 会自动实现一个默认的可用于进程间传参通信的void basicTypes(...)函数,其参数是java的几种基础数据类型

除此之外,AIDL还支持多种其他数据类型:byte、short、char、charSequence、 List、 Map等

除了AndroidStudio自动创建的basicTypes(...)函数,我在AIDL文件里面再新增一个setData(..)函数,用于后面跨进程的数据传输,虽然使用AndroidStudio自动生成的basicTypes(...)也是可以的,但是自己创建一个函数会更具有代表性

在本篇博文最开始就阐述过,AIDL的本质是对Binder的运用,从而实现进程间通信

那么现在Binder在哪呢?

IAppAidlInterface.aidl文件创建之后,build一下工程,AndroidStudio会在build目录下创建一个aidl_source_output_dir文件夹,同时在这个文件夹下创建与IAppAidlInterface.aidl包名、文件名相同的文件夹目录和java文件

IAppAidlInterface.java文件中通过继承android.os.Binder创建一个抽象的代理类stub,这个stub抽象代理类主要做如下几件事:

  • 通过stub自身实例实现进程内部的通信
  • 通过实现一个内部代理类Porxy用于跨进程通信
  • 重写Binder中的onTransact()函数,实现AIDL接口文件中声明的函数进行数据传输

传输的数据必须是序列化的android.os.Parcel类型数据 

 

当然,如果项目需要对AIDL的Binder实现过程进行自定义封装,方便项目中对进程间通信机制进行定制化,那么,完全可以不采用AndroidStudio自动生成的IAppAidlInterface.java只须要按照自己的需要实现IAppAidlInterface.java中对Binder进程间通信的实现过程就行了

因为归根结底,AIDL实现进程间通信的基础就是Binder机制,只要使用Binder实现AIDL进程间通信的目的就可以了

IAppAidlInterface.java就先讨论到这里,这篇博文主要是对AIDL的使用进行研究,其对Binder机制的实现与封装不在此做深入探讨

后续会专门开一篇博文讲解AIDL对Binder机制的内部实现,以及用户如何自定义封装

四.otherapp中也实现AIDL

上一节中,作为服务端的mainapp里创建了一个AIDL文件,客户端的otherapp中也需要实现一份相同的AIDL,要不然客户端就无法引用到了对应的函数和stub等了

很简单,把mainapp中的AIDL文件整个包名目录直接拷贝到otherapp中即可,然后再build一下工程

接下来,需要添加一些代码,实现客户端otherapp与服务端mainapp的相连

五.mainapp中添加代码

前文中已经展示过,MainAppService会随着MainAppActivity的onCreate()和onDestroy()生命周期startService()和stopService()

mainapp中要添加的代码在MainAppService.java中,需要在MainAppService中做下面一些事情:

  • 使用匿名内部类实现IAppAidlInterface.Stub抽象类,用于实现IAppAidlInterface.aidl中的接口函数和onBinder()时返回匿名内部类实例
  • onBinder()中启动一个线程,每1秒轮循接收客户端发送过来的数据

      这里提到个题外的知识点,Service中除了onBinder()函数外还有个onRebind()函数

      如果同一客户端每次unBindService()之后再bindService()并且发送的Intent也一样,那么onBind()就只会在服务端第一次被这个客户端连接时才执行,后续重连时都不会再执行了。

     而onRebind()在服务端第一次被连接时不会被执行,但是之后每次重连都会执行,不论Intent是否一样。

    如果想要onBind()在同一客户端连接时都能执行,客户端在每次bindService()时,改变发送Intenttype或其他成员变量就行了

  • 定义一个string变量用于接收客户端传过来的字符串,定义一个boolean变量用于控制线程
  • AndroidMainfest.xml中为MainAppService添加Service标签

六.otherapp中添加代码

otherapp里面主要需要做如下几件事:

  • 新建一个Intent,用于连接服务端mainapp
    IntentComponent设置为Sevice的包名和类名
  • 新建两个button,用于控制bindService()绑定和unbindService()解绑
  • 重写Service连接和断开的两个基础函数onServiceConnected()onServiceDisconnected()
  • AndroidMainfest.xml中添加查询包名权限,以便otherapp可以查询到mainapp,或者直接指定查询mainapp的包名

七.运行、验证 

到此,一个最基础的使用AIDL实现两个App(服务端mainapp、客户端otherapp)之间通信的demo代码就完成了,下面我们来验证一下。

编译、安装apk:

项目build Apk后会生成两个apk,两个都install上

 

运行验证:

注:本demo中代码的所有日志TAG都加上了AIDL前缀,方便日志打印验证

先启动一下mainapp,MainAppService不会被启动但是会被注册到系统,因为在mainapp的AndroidMainfest.xml中对MainAppService进行了Service标签添加。

退出mainapp后,再打开otherapp:

现在执行几次"Bind Service"和"Unbind Service",就会看到如下日志打印:

好,通过这个精简Demo,初步实现了两个App通过AIDL的跨进程通信 

八.源代码

接下来逐一展示实现的源码

mainapp源码:

D:\Codes\aidl-test\app\class="lazy" data-src\main\aidl\com\android\mainapp\IAppAidlInterface.aidl

// IAppAidlInterface.aidlpackage com.android.mainapp;// Declare any non-default types here with import statementsinterface IAppAidlInterface {        void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,            double aDouble, String aString);    void setStringData(String strData);}

D:\Codes\aidl-test\app\class="lazy" data-src\main\java\com\android\mainapp\MainAppActivity.java

package com.android.mainapp;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.os.Bundle;import android.util.Log;public class MainAppActivity extends AppCompatActivity {    private String TAG = "AIDL-MainAppActivity";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.v(TAG, "onCreate()");        setContentView(R.layout.activity_main);    }    @Override    protected void onDestroy() {        super.onDestroy();        Log.v(TAG, "onDestroy()");    }}

D:\Codes\aidl-test\app\class="lazy" data-src\main\java\com\android\mainapp\MainAppService.java

package com.android.mainapp;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;public class MainAppService extends Service {    private String TAG = "AIDL-MainAppService";    private String mStrData;    private boolean mSetServiceRunning = true;    public MainAppService() {    }    @Override    public void onCreate() {        super.onCreate();        Log.v(TAG, "onStart()");    }    @Override    public void onStart(Intent intent, int startId) {        Log.v(TAG, "onStart()");    }    IAppAidlInterface.Stub mStub = new IAppAidlInterface.Stub() {        @Override        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {        }        @Override        public void setStringData(String strData) {            mStrData = strData;        }    };    @Override    public IBinder onBind(Intent intent) {        Log.v(TAG, "onBind()");        mSetServiceRunning = true;        new Thread() {            @Override            public void run() {                super.run();                while (mSetServiceRunning) {                    try {                        Thread.sleep(1000);                        Log.v(TAG, "mStrData:"+mStrData);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }.start();        return mStub;    }    @Override    public boolean onUnbind(Intent intent) {        Log.v(TAG, "onUnbind()");        mSetServiceRunning = false;        return true;    }    @Override    public void onDestroy() {        super.onDestroy();        Log.v(TAG, "onDestroy()");    }}

D:\Codes\aidl-test\app\class="lazy" data-src\main\AndroidManifest.xml

                                                                                                            

otherapp源码: 

D:\Codes\aidl-test\otherapp\class="lazy" data-src\main\aidl\com\android\mainapp\IAppAidlInterface.aidl

// IAppAidlInterface.aidlpackage com.android.mainapp;// Declare any non-default types here with import statementsinterface IAppAidlInterface {        void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,            double aDouble, String aString);    void setStringData(String strData);}

D:\Codes\aidl-test\otherapp\class="lazy" data-src\main\java\com\android\otherapp\OtherAppMainActivity.java

package com.android.otherapp;import androidx.appcompat.app.AppCompatActivity;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.util.Log;import android.view.View;import com.android.mainapp.IAppAidlInterface;public class OtherAppMainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection {    private String TAG = "AIDL-OtherAppActivity";    private int mICount = 0;    private Intent mServiceIntent;    private IAppAidlInterface mBinder;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_other_app_main);        mServiceIntent = new Intent();        mServiceIntent.setComponent(new ComponentName("com.android.mainapp", "com.android.mainapp.MainAppService"));        findViewById(R.id.btnBindMainAppService).setOnClickListener(this);        findViewById(R.id.btnUnBindMainAppService).setOnClickListener(this);    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.btnBindMainAppService: {                Log.v(TAG, "onClick():btnBindMainAppService");                bindService(mServiceIntent, this, Context.BIND_AUTO_CREATE);            }            break;            case R.id.btnUnBindMainAppService: {                Log.v(TAG, "onClick():btnUnBindMainAppService");                unbindService(this);                mBinder = null;            }            break;        }    }    @Override    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {        if (mBinder == null) {            mBinder = IAppAidlInterface.Stub.asInterface(iBinder);            mICount++;            Log.v(TAG, "onServiceConnected() 第 " + mICount + " 次");            try {                String strData = "第" + mICount + "次连接Service成功!";                mBinder.setStringData(strData);            } catch (RemoteException e) {                e.printStackTrace();            }        }    }    @Override    public void onServiceDisconnected(ComponentName componentName) {        Log.v(TAG, "onServiceDisconnected");    }}

D:\Codes\aidl-test\otherapp\class="lazy" data-src\main\res\layout\activity_other_app_main.xml

        

D:\Codes\aidl-test\otherapp\class="lazy" data-src\main\AndroidManifest.xml

                                                                                                                

来源地址:https://blog.csdn.net/geyichongchujianghu/article/details/130045373

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android:AIDL实战详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

for update 详解及实战

文章目录 一、for update 是什么?二、我们通常什么情况下会用到它?1 .在我们的实际业务场景中,有些情况并发量不太高,为了保证数据的正确性,使用悲观锁也可以 三、select……for update会锁表还是锁行?1.
2023-08-20

ElasticSearch动态映射实战详解

这篇文章主要为大家介绍了ElasticSearch动态映射实战详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-31

PHP 设计模式实战详解

设计模式为软件设计提供经过验证的解决方案,解决常见编程问题。本文深入探讨 php 中的常用设计模式,并通过实战案例进行阐述,涵盖单例模式、工厂方法模式和观察者模式。PHP 设计模式实战详解设计模式为软件设计提供了一套经过验证的解决方案,以
PHP 设计模式实战详解
2024-05-07

selenium鼠标操作实战案例详解

在实际场景中,会有单击、长时间单击、双击、右键、拖拽等鼠标操作,selenium提供了名为ActionChains的类来处理这些操作,下面这篇文章主要给大家介绍了关于selenium鼠标操作实战案例的相关资料,需要的朋友可以参考下
2023-05-20

Python算法应用实战之栈详解

栈(stack) 栈又称之为堆栈是一个特殊的有序表,其插入和删除操作都在栈顶进行操作,并且按照先进后出,后进先出的规则进行运作。 如下图所示例如枪的弹匣,第一颗放进弹匣的子弹反而在发射出去的时候是最后一个,而最后放入弹匣的一颗子弹在打出去的
2022-06-04

JVM jstack实战之死锁问题详解

如果在生产环境发生了死锁,我们将看到的是部署的程序没有任何反应了,这个时候我们可以借助 jstack进行分析,下面我们实战操作查找死锁的原因
2022-11-13

Redis实战之Jedis使用技巧详解

目录一、摘要二、Jedis2.1、基本使用2.2、连接池2.3、连接池配置2.4、字符串常用 API 操作2.5、哈希常用 API 操作2.6、列表常用 API 操作2.7、集合常用 API 操作2.8、有序集合常用 API 操作三、集群配
2022-12-22

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录