赞
踩
AIDL:Android Interface Definition Language
AIDL是为了实现进程间通信而设计的Android接口语言
Android进程间通信有多种方式,Binder机制是其中最常见的一种
AIDL的本质就是基于对Binder的运用从而实现进程间通信
这篇博文从实战出发,用一个尽可能精简的Demo,实现两个App(也是两个进程:服务端mainapp、客户端otherapp)通过AIDL的跨进程通信
废话不多说,开撸!
按照下列步骤先创建两个App:
(1).新建一个开发文件夹(本Demo中命名为aidl-test)
(2).使用AndroidStudio在aidl-test文件夹下创建第一个Empty Activity的空App:mainapp
为了后续方便起见
创建完成后,把Studio默认创建的MainActivity.java名字改一下,改成MainAppActivty.java
(3).创建第二个Empty Activity的空App:otherapp
两个空App创建完成了:
上一节中新建了两个空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.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()");
- }
- }
依然使用方便又快捷的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抽象代理类主要做如下几件事:
传输的数据必须是序列化的android.os.Parcel类型数据
当然,如果项目需要对AIDL的Binder实现过程进行自定义封装,方便项目中对进程间通信机制进行定制化,那么,完全可以不采用AndroidStudio自动生成的IAppAidlInterface.java,只须要按照自己的需要实现IAppAidlInterface.java中对Binder进程间通信的实现过程就行了
因为归根结底,AIDL实现进程间通信的基础就是Binder机制,只要使用Binder实现AIDL进程间通信的目的就可以了
IAppAidlInterface.java就先讨论到这里,这篇博文主要是对AIDL的使用进行研究,其对Binder机制的实现与封装不在此做深入探讨
后续会专门开一篇博文讲解AIDL对Binder机制的内部实现,以及用户如何自定义封装
上一节中,作为服务端的mainapp里创建了一个AIDL文件,客户端的otherapp中也需要实现一份相同的AIDL,要不然客户端就无法引用到了对应的函数和stub等了
很简单,把mainapp中的AIDL文件整个包名目录直接拷贝到otherapp中即可,然后再build一下工程
接下来,需要添加一些代码,实现客户端otherapp与服务端mainapp的相连
前文中已经展示过,MainAppService会随着MainAppActivity的onCreate()和onDestroy()生命周期startService()和stopService()
mainapp中要添加的代码在MainAppService.java中,需要在MainAppService中做下面一些事情:
这里提到个题外的知识点,Service中除了onBinder()函数外还有个onRebind()函数
如果同一客户端每次unBindService()之后再bindService()并且发送的Intent也一样,那么onBind()就只会在服务端第一次被这个客户端连接时才执行,后续重连时都不会再执行了。
而onRebind()在服务端第一次被连接时不会被执行,但是之后每次重连都会执行,不论Intent是否一样。
如果想要onBind()在同一客户端连接时都能执行,客户端在每次bindService()时,改变发送Intent的type或其他成员变量就行了
otherapp里面主要需要做如下几件事:
到此,一个最基础的使用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
- // IAppAidlInterface.aidl
- package com.android.mainapp;
-
- // Declare any non-default types here with import statements
-
- interface 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";
-
- @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\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\src\main\AndroidManifest.xml
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools">
-
- <application
- android:allowBackup="true"
- android:dataExtractionRules="@xml/data_extraction_rules"
- android:fullBackupContent="@xml/backup_rules"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true"
- android:theme="@style/Theme.Mainapp"
- tools:targetApi="31">
- <service
- android:name=".MainAppService"
- android:enabled="true"
- android:exported="true">
- </service>
-
- <activity
- android:name=".MainAppActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
-
- <meta-data
- android:name="android.app.lib_name"
- android: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 statements
-
- interface 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;
-
- @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\src\main\res\layout\activity_other_app_main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- 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"
- android:orientation="vertical"
- tools:context=".OtherAppActivity">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAllCaps="false"
- android:text="OtherApp"/>
-
- <Button
- android:id="@+id/btnBindMainAppService"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAllCaps="false"
- android:text="Bind Service" />
-
- <Button
- android:id="@+id/btnUnBindMainAppService"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAllCaps="false"
- android:text="UnBind Service" />
-
- </LinearLayout>
D:\Codes\aidl-test\otherapp\src\main\AndroidManifest.xml
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android">
-
- <!--<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>-->
- <queries>
- <package android:name="com.android.mainapp"/>
- </queries>
-
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true"
- android:theme="@style/Theme.Mainapp">
- <activity
- android:name=".OtherAppMainActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
-
- <meta-data
- android:name="android.app.lib_name"
- android:value="" />
- </activity>
- </application>
-
- </manifest>
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。