Android生成Java AIDL

玛卡巴卡的卡巴卡玛  金牌会员 | 2024-9-12 15:00:08 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 650|帖子 650|积分 1950

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):被客户端解绑时实行
  1. @com/android/mainapp/MainAppActivity.java
  2. package com.android.mainapp;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.content.Intent;
  5. import android.os.Bundle;
  6. import android.util.Log;
  7. public class MainAppActivity extends AppCompatActivity {
  8.     private String TAG = "AIDL-MainAppActivity";
  9.     @Override
  10.     protected void onCreate(Bundle savedInstanceState) {
  11.         super.onCreate(savedInstanceState);
  12.         Log.v(TAG, "onCreate()");
  13.         setContentView(R.layout.activity_main);
  14.     }
  15.     @Override
  16.     protected void onDestroy() {
  17.         super.onDestroy();
  18.         Log.v(TAG, "onDestroy()");
  19.     }
  20. }
复制代码
  1. @com/android/mainapp/MainAppService.java
  2. package com.android.mainapp;
  3. import android.app.Service;
  4. import android.content.Intent;
  5. import android.os.IBinder;
  6. import android.util.Log;
  7. public class MainAppService extends Service {
  8.     private String TAG = "AIDL-MainAppService";
  9.     public MainAppService() {
  10.     }
  11.     @Override
  12.     public void onCreate() {
  13.         super.onCreate();
  14.     }
  15.     @Override
  16.     public void onStart(Intent intent, int startId) {
  17.         Log.v(TAG, "onStart()");
  18.     }
  19.     @Override
  20.     public IBinder onBind(Intent intent) {
  21.         // TODO: Return the communication channel to the service.
  22.         throw new UnsupportedOperationException("Not yet implemented");
  23.     }
  24.     @Override
  25.     public boolean onUnbind(Intent intent) {
  26.         Log.v(TAG, "onUnbind()");
  27.         return true;
  28.     }
  29.     @Override
  30.     public void onDestroy() {
  31.         super.onDestroy();
  32.         Log.v(TAG, "onDestroy()");
  33.     }
  34. }
复制代码
三.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()时,改变发送Intent的type或其他成员变量就行了
界说一个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\src\main\aidl\com\android\mainapp\IAppAidlInterface.aidl
  1. // IAppAidlInterface.aidl
  2. package com.android.mainapp;
  3. // Declare any non-default types here with import statements
  4. interface IAppAidlInterface {
  5.     /**
  6.      * Demonstrates some basic types that you can use as parameters
  7.      * and return values in AIDL.
  8.      */
  9.     void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
  10.             double aDouble, String aString);
  11.     void setStringData(String strData);
  12. }
复制代码
 
D:\Codes\aidl-test\app\src\main\java\com\android\mainapp\MainAppActivity.java
  1. package com.android.mainapp;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.util.Log;
  6. public class MainAppActivity extends AppCompatActivity {
  7.     private String TAG = "AIDL-MainAppActivity";
  8.     @Override
  9.     protected void onCreate(Bundle savedInstanceState) {
  10.         super.onCreate(savedInstanceState);
  11.         Log.v(TAG, "onCreate()");
  12.         setContentView(R.layout.activity_main);
  13.     }
  14.     @Override
  15.     protected void onDestroy() {
  16.         super.onDestroy();
  17.         Log.v(TAG, "onDestroy()");
  18.     }
  19. }
复制代码
D:\Codes\aidl-test\app\src\main\java\com\android\mainapp\MainAppService.java
  1. package com.android.mainapp;
  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.IBinder;
  5. import android.os.RemoteException;
  6. import android.util.Log;
  7. public class MainAppService extends Service {
  8.     private String TAG = "AIDL-MainAppService";
  9.     private String mStrData;
  10.     private boolean mSetServiceRunning = true;
  11.     public MainAppService() {
  12.     }
  13.     @Override
  14.     public void onCreate() {
  15.         super.onCreate();
  16.         Log.v(TAG, "onStart()");
  17.     }
  18.     @Override
  19.     public void onStart(Intent intent, int startId) {
  20.         Log.v(TAG, "onStart()");
  21.     }
  22.     IAppAidlInterface.Stub mStub = new IAppAidlInterface.Stub() {
  23.         @Override
  24.         public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
  25.         }
  26.         @Override
  27.         public void setStringData(String strData) {
  28.             mStrData = strData;
  29.         }
  30.     };
  31.     @Override
  32.     public IBinder onBind(Intent intent) {
  33.         Log.v(TAG, "onBind()");
  34.         mSetServiceRunning = true;
  35.         new Thread() {
  36.             @Override
  37.             public void run() {
  38.                 super.run();
  39.                 while (mSetServiceRunning) {
  40.                     try {
  41.                         Thread.sleep(1000);
  42.                         Log.v(TAG, "mStrData:"+mStrData);
  43.                     } catch (InterruptedException e) {
  44.                         e.printStackTrace();
  45.                     }
  46.                 }
  47.             }
  48.         }.start();
  49.         return mStub;
  50.     }
  51.     @Override
  52.     public boolean onUnbind(Intent intent) {
  53.         Log.v(TAG, "onUnbind()");
  54.         mSetServiceRunning = false;
  55.         return true;
  56.     }
  57.     @Override
  58.     public void onDestroy() {
  59.         super.onDestroy();
  60.         Log.v(TAG, "onDestroy()");
  61.     }
  62. }
复制代码
D:\Codes\aidl-test\app\src\main\AndroidManifest.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:tools="http://schemas.android.com/tools">
  4.     <application
  5.         android:allowBackup="true"
  6.         android:dataExtractionRules="@xml/data_extraction_rules"
  7.         android:fullBackupContent="@xml/backup_rules"
  8.         android:icon="@mipmap/ic_launcher"
  9.         android:label="@string/app_name"
  10.         android:roundIcon="@mipmap/ic_launcher_round"
  11.         android:supportsRtl="true"
  12.         android:theme="@style/Theme.Mainapp"
  13.         tools:targetApi="31">
  14.         <service
  15.             android:name=".MainAppService"
  16.             android:enabled="true"
  17.             android:exported="true">
  18.         </service>
  19.         <activity
  20.             android:name=".MainAppActivity"
  21.             android:exported="true">
  22.             <intent-filter>
  23.                 <action android:name="android.intent.action.MAIN" />
  24.                 <category android:name="android.intent.category.LAUNCHER" />
  25.             </intent-filter>
  26.             <meta-data
  27.                 android:name="android.app.lib_name"
  28.                 android:value="" />
  29.         </activity>
  30.     </application>
  31. </manifest>
复制代码
 
otherapp源码: 

D:\Codes\aidl-test\otherapp\src\main\aidl\com\android\mainapp\IAppAidlInterface.aidl
  1. // IAppAidlInterface.aidl
  2. package com.android.mainapp;
  3. // Declare any non-default types here with import statements
  4. interface IAppAidlInterface {
  5.     /**
  6.      * Demonstrates some basic types that you can use as parameters
  7.      * and return values in AIDL.
  8.      */
  9.     void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
  10.             double aDouble, String aString);
  11.     void setStringData(String strData);
  12. }
复制代码
D:\Codes\aidl-test\otherapp\src\main\java\com\android\otherapp\OtherAppMainActivity.java
  1. package com.android.otherapp;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.content.ComponentName;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.ServiceConnection;
  7. import android.os.Bundle;
  8. import android.os.IBinder;
  9. import android.os.RemoteException;
  10. import android.util.Log;
  11. import android.view.View;
  12. import com.android.mainapp.IAppAidlInterface;
  13. public class OtherAppMainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection {
  14.     private String TAG = "AIDL-OtherAppActivity";
  15.     private int mICount = 0;
  16.     private Intent mServiceIntent;
  17.     private IAppAidlInterface mBinder;
  18.     @Override
  19.     protected void onCreate(Bundle savedInstanceState) {
  20.         super.onCreate(savedInstanceState);
  21.         setContentView(R.layout.activity_other_app_main);
  22.         mServiceIntent = new Intent();
  23.         mServiceIntent.setComponent(new ComponentName("com.android.mainapp", "com.android.mainapp.MainAppService"));
  24.         findViewById(R.id.btnBindMainAppService).setOnClickListener(this);
  25.         findViewById(R.id.btnUnBindMainAppService).setOnClickListener(this);
  26.     }
  27.     @Override
  28.     public void onClick(View view) {
  29.         switch (view.getId()) {
  30.             case R.id.btnBindMainAppService: {
  31.                 Log.v(TAG, "onClick():btnBindMainAppService");
  32.                 bindService(mServiceIntent, this, Context.BIND_AUTO_CREATE);
  33.             }
  34.             break;
  35.             case R.id.btnUnBindMainAppService: {
  36.                 Log.v(TAG, "onClick():btnUnBindMainAppService");
  37.                 unbindService(this);
  38.                 mBinder = null;
  39.             }
  40.             break;
  41.         }
  42.     }
  43.     @Override
  44.     public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
  45.         if (mBinder == null) {
  46.             mBinder = IAppAidlInterface.Stub.asInterface(iBinder);
  47.             mICount++;
  48.             Log.v(TAG, "onServiceConnected() 第 " + mICount + " 次");
  49.             try {
  50.                 String strData = "第" + mICount + "次连接Service成功!";
  51.                 mBinder.setStringData(strData);
  52.             } catch (RemoteException e) {
  53.                 e.printStackTrace();
  54.             }
  55.         }
  56.     }
  57.     @Override
  58.     public void onServiceDisconnected(ComponentName componentName) {
  59.         Log.v(TAG, "onServiceDisconnected");
  60.     }
  61. }
复制代码
 
D:\Codes\aidl-test\otherapp\src\main\res\layout\activity_other_app_main.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout
  3.     xmlns:android="http://schemas.android.com/apk/res/android"
  4.     xmlns:app="http://schemas.android.com/apk/res-auto"
  5.     xmlns:tools="http://schemas.android.com/tools"
  6.     android:layout_width="match_parent"
  7.     android:layout_height="match_parent"
  8.     android:orientation="vertical"
  9.     tools:context=".OtherAppActivity">
  10.     <TextView
  11.         android:layout_width="wrap_content"
  12.         android:layout_height="wrap_content"
  13.         android:textAllCaps="false"
  14.         android:text="OtherApp"/>
  15.     <Button
  16.         android:id="@+id/btnBindMainAppService"
  17.         android:layout_width="wrap_content"
  18.         android:layout_height="wrap_content"
  19.         android:textAllCaps="false"
  20.         android:text="Bind  Service" />
  21.     <Button
  22.         android:id="@+id/btnUnBindMainAppService"
  23.         android:layout_width="wrap_content"
  24.         android:layout_height="wrap_content"
  25.         android:textAllCaps="false"
  26.         android:text="UnBind Service" />
  27. </LinearLayout>
复制代码
D:\Codes\aidl-test\otherapp\src\main\AndroidManifest.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android">
  3.     <!--<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>-->
  4.     <queries>
  5.         <package android:name="com.android.mainapp"/>
  6.     </queries>
  7.     <application
  8.         android:allowBackup="true"
  9.         android:icon="@mipmap/ic_launcher"
  10.         android:label="@string/app_name"
  11.         android:roundIcon="@mipmap/ic_launcher_round"
  12.         android:supportsRtl="true"
  13.         android:theme="@style/Theme.Mainapp">
  14.         <activity
  15.             android:name=".OtherAppMainActivity"
  16.             android:exported="true">
  17.             <intent-filter>
  18.                 <action android:name="android.intent.action.MAIN" />
  19.                 <category android:name="android.intent.category.LAUNCHER" />
  20.             </intent-filter>
  21.             <meta-data
  22.                 android:name="android.app.lib_name"
  23.                 android:value="" />
  24.         </activity>
  25.     </application>
  26. </manifest>
复制代码
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

玛卡巴卡的卡巴卡玛

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表