专业建站商,收费wordpress,中国购物平台排名,越秀seo搜索引擎优化AIDL:Android Interface Definition Language
AIDL是为了实现进程间通信而设计的Android接口语言
Android进程间通信有多种方式#xff0c;Binder机制是其中最常见的一种
AIDL的本质就是基于对Binder的运用从而实现进程间通信
这篇博文从实战出发#xff0c;用一个尽可能…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的空Appmainapp
为了后续方便起见
创建完成后把Studio默认创建的MainActivity.java名字改一下改成MainAppActivty.java (3).创建第二个Empty Activity的空Appotherapp 两个空App创建完成了 二.在mainapp中创建一个Service
上一节中新建了两个空App:mainapp和otherapp
现在就先在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.javapackage 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;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.v(TAG, onCreate());setContentView(R.layout.activity_main);}Overrideprotected 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() {}Overridepublic void onCreate() {super.onCreate();}Overridepublic void onStart(Intent intent, int startId) {Log.v(TAG, onStart());}Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.throw new UnsupportedOperationException(Not yet implemented);}Overridepublic boolean onUnbind(Intent intent) {Log.v(TAG, onUnbind());return true;}Overridepublic 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()时改变发送Intent的type或其他成员变量就行了
定义一个string变量用于接收客户端传过来的字符串定义一个boolean变量用于控制线程 AndroidMainfest.xml中为MainAppService添加Service标签 六.otherapp中添加代码
otherapp里面主要需要做如下几件事
新建一个Intent用于连接服务端mainappIntent的Component设置为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前缀方便日志打印验证
先启动一下mainappMainAppService不会被启动但是会被注册到系统因为在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
// IAppAidlInterface.aidl
package com.android.mainapp;// Declare any non-default types here with import statementsinterface IAppAidlInterface {/*** 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);void setStringData(String strData);
} D:\Codes\aidl-test\app\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;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.v(TAG, onCreate());setContentView(R.layout.activity_main);}Overrideprotected void onDestroy() {super.onDestroy();Log.v(TAG, onDestroy());}
}
D:\Codes\aidl-test\app\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() {}Overridepublic void onCreate() {super.onCreate();Log.v(TAG, onStart());}Overridepublic void onStart(Intent intent, int startId) {Log.v(TAG, onStart());}IAppAidlInterface.Stub mStub new IAppAidlInterface.Stub() {Overridepublic void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {}Overridepublic void setStringData(String strData) {mStrData strData;}};Overridepublic IBinder onBind(Intent intent) {Log.v(TAG, onBind());mSetServiceRunning true;new Thread() {Overridepublic void run() {super.run();while (mSetServiceRunning) {try {Thread.sleep(1000);Log.v(TAG, mStrData:mStrData);} catch (InterruptedException e) {e.printStackTrace();}}}}.start();return mStub;}Overridepublic boolean onUnbind(Intent intent) {Log.v(TAG, onUnbind());mSetServiceRunning false;return true;}Overridepublic void onDestroy() {super.onDestroy();Log.v(TAG, onDestroy());}
}
D:\Codes\aidl-test\app\src\main\AndroidManifest.xml
?xml version1.0 encodingutf-8?
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsapplicationandroid:allowBackuptrueandroid:dataExtractionRulesxml/data_extraction_rulesandroid:fullBackupContentxml/backup_rulesandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/Theme.Mainapptools:targetApi31serviceandroid:name.MainAppServiceandroid:enabledtrueandroid:exportedtrue/serviceactivityandroid:name.MainAppActivityandroid:exportedtrueintent-filteraction android:nameandroid.intent.action.MAIN /category android:nameandroid.intent.category.LAUNCHER //intent-filtermeta-dataandroid:nameandroid.app.lib_nameandroid:value //activity/application/manifest otherapp源码 D:\Codes\aidl-test\otherapp\src\main\aidl\com\android\mainapp\IAppAidlInterface.aidl
// IAppAidlInterface.aidl
package com.android.mainapp;// Declare any non-default types here with import statementsinterface IAppAidlInterface {/*** 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);void setStringData(String strData);
}
D:\Codes\aidl-test\otherapp\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;Overrideprotected 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);}Overridepublic 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;}}Overridepublic 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();}}}Overridepublic void onServiceDisconnected(ComponentName componentName) {Log.v(TAG, onServiceDisconnected);}
} D:\Codes\aidl-test\otherapp\src\main\res\layout\activity_other_app_main.xml
?xml version1.0 encodingutf-8?
LinearLayoutxmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationverticaltools:context.OtherAppActivityTextViewandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:textAllCapsfalseandroid:textOtherApp/Buttonandroid:idid/btnBindMainAppServiceandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:textAllCapsfalseandroid:textBind Service /Buttonandroid:idid/btnUnBindMainAppServiceandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:textAllCapsfalseandroid:textUnBind Service //LinearLayout
D:\Codes\aidl-test\otherapp\src\main\AndroidManifest.xml
?xml version1.0 encodingutf-8?
manifest xmlns:androidhttp://schemas.android.com/apk/res/android!--uses-permission android:nameandroid.permission.QUERY_ALL_PACKAGES/--queriespackage android:namecom.android.mainapp//queriesapplicationandroid:allowBackuptrueandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/Theme.Mainappactivityandroid:name.OtherAppMainActivityandroid:exportedtrueintent-filteraction android:nameandroid.intent.action.MAIN /category android:nameandroid.intent.category.LAUNCHER //intent-filtermeta-dataandroid:nameandroid.app.lib_nameandroid:value //activity/application/manifest