写在前面的话:
关于remote service中使用aidl来实现跨进程,多线程通信,我是参考了三篇文章,大概把这个弄明白了。
(1)android 官方关于aidl的说明文档
docs/guide/components/aidl.html
(2)https://www.jianshu.com/p/83bdeac67ee7
Android Studio 创建AIDL Demo
aidl的官方描述:
AIDL (Android Interface Definition Language) is similar to other IDLs you might have worked with. It allows you to define the programming interface that both the client and service agree upon in order to communicate with each other using interprocess communication (IPC).
AIDL(android接口定义语言)与IDLs类似,他主要是定义客户端与服务器统一的编程接口以便让客户端与服务器端跨进程通信(IPC)。
什么地方使用aidl:
Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger.
如果clients要从不同应用跨进程访问service,在service中处理多线程操作。我们才会使用AIDL。如果不需要跨进程,我们可以创建实现Binder的接口,如果我们需要跨进程通信,但是不需要处理多线程操作,那么,我们可以使用Messager.
如何使用aidl:
To create a bounded service using AIDL, follow these steps:
##1. Create the .aidl file
This file defines the programming interface with method signatures.
##2. Implement the interface
The Android SDK tools generate an interface in the Java programming language, based on your .aidl file. This interface has an inner abstract class named Stub that extends Binder and implements methods from your AIDL interface. You must extend the Stub class and implement the methods.
##3. Expose the interface to clients
Implement a Service and override onBind() to return your implementation of the Stub class.
#aidl使用的详细步骤
我以官方文档和另外一个样例,写了一个Demo来说明如何实现aidl的
使用。
服务端
这是我的服务端的代码结构:

###创建aidl文件(IMyAidlInterface.aidl):
// IMyAidlInterface.aidl
package com.android.aidldemo;
import com.android.aidldemo.Rect;
import com.android.aidldemo.Person;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* 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 getPid();
void onRemoteServiceDo();
void onProcessRect(in Rect rect);
Rect getRect();
Person getPerson();
void savePerson(in Person person);
}
我们定义 7个接口,其中getPid(),onRemoteServiceDo()处理基本的数据类型,onProcessRect和getRect方法处理自定义的数据类型Rect,getPerson和savePerson方法处理自定义数据类型Person.
编写Aidl文件时,需要注意的地方:
- 接口名和aidl文件名相同
- 接口和方法前不用加访问权限修饰符public,private,protected等,也不能用final,static
- Aidl默认支持的类型包话java基本类型(int、long、boolean)和(String、List、Map、CharSequence),使用这些类型时不需要import声明。对于List和Map中的元素类型必须是Aidl支持的类型。如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口
- 自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中
- 在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,以指明参数是输入参数、输出参数还是输入输出参数
- Java原始类型默认的标记为in,不能为其它标记
###aidl中自定义数据类型
我们的样例中,aidl中使用了二个自定义的数据类型(Rect,Person)。使用自定义的类,我们必须让此类实现Parcelable接口,重写describeContents和writeToParcel方法,并且要定义一个Parcelable.Creator 类型的变量CREATOR。
- 类Rect
package com.android.aidldemo;
import android.os.Parcel;
import android.os.Parcelable;
public class Rect implements Parcelable{
public int left;
public int top;
public int right;
public int bottom;
public static final Creator<Rect> CREATOR
= new Creator<Rect>() {
@Override
public Rect createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return new Rect(source);
}
@Override
public Rect[] newArray(int size) {
// TODO Auto-generated method stub
return new Rect[size];
}
};
public Rect() {
}
public Rect(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
private Rect(Parcel in) {
readFromParcel(in);
}
private void readFromParcel(Parcel in) {
// TODO Auto-generated method stub
left = in.readInt();
top = in.readInt();
right = in.readInt();
bottom = in.readInt();
}
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
// TODO Auto-generated method stub
out.writeInt(left);
out.writeInt(top);
out.writeInt(right);
out.writeInt(bottom);
}
@Override
public String toString() {
// TODO Auto-generated method stub
return super.toString()
+"--left:"+left
+"--top:"+top
+"--right:"+right
+"--bottom:"+bottom;
}
}
- 类Person
package com.android.aidldemo;
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable{
private int id;
private String name;
public Person() {
}
public Person(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void writeToParcel(Parcel dest, int arg1) {
// TODO Auto-generated method stub
dest.writeInt(id);
dest.writeString(name);
}
public static final Creator<Person> CREATOR
= new Creator<Person>() {
@Override
public Person createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return new Person(source.readInt(), source.readString());
}
@Override
public Person[] newArray(int size) {
// TODO Auto-generated method stub
return new Person[size];
}
};
@Override
public String toString() {
// TODO Auto-generated method stub
return super.toString()
+"--id:"+id
+"--name:"+name;
}
}
###声明自定义的数据类型
我们在自定义的数据类型所在包下创建一个aidl文件对自定义类型进行声明,文件的名称与自定义类型同名。例如,Person.aidl声明Person类,Rect.aidl声明Rect类。
- Person.aidl
// Person.aidl
package com.android.aidldemo;
parcelable Person;
- Rect.aidl
// Rect.aidl
package com.android.aidldemo;
parcelable Rect;
实现aidl的接口
我们使用RemoteService.java来实现aidl接口:
package com.android.aidl.server;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import com.android.aidldemo.IMyAidlInterface;
import com.android.aidldemo.Person;
import com.android.aidldemo.Rect;
public class RemoteService extends Service{
private final static String TAG ="RemoteService";
private Rect rect = new Rect(0, 0, 100, 100);
private Person person = new Person(1,"name_1");
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) throws RemoteException {
Log.i(TAG,"RemoteService--basicTypes(" + anInt + "," + aLong + "," + aBoolean
+ "," + aFloat + "," + aDouble + "," + aString);
}
public int getPid(){
Log.i(TAG,"RemoteService--getPid():" + Process.myPid());
return Process.myPid();
}
@Override
public void onRemoteServiceDo() throws RemoteException {
// TODO Auto-generated method stub
Log.i(TAG, "RemoteService--onRemoteServiceDo()");
}
@Override
public Rect getRect() throws RemoteException {
// TODO Auto-generated method stub
Log.i(TAG, "RemoteService--getRect():" + rect);
return rect;
}
@Override
public void onProcessRect(Rect rect)
throws RemoteException {
// TODO Auto-generated method stub
RemoteService.this.rect.left = rect.left;
RemoteService.this.rect.top = rect.top;
RemoteService.this.rect.right = rect.right;
RemoteService.this.rect.bottom = rect.bottom;
Log.i(TAG, "RemoteService--onProcessRect:" + RemoteService.this.rect);
}
@Override
public Person getPerson() throws RemoteException {
// TODO Auto-generated method stub
Log.i(TAG, "RemoteService--getPerson():" + RemoteService.this.person);
return person;
}
@Override
public void savePerson(Person person) throws RemoteException {
// TODO Auto-generated method stub
RemoteService.this.person.setId(person.getId());
RemoteService.this.person.setName(person.getName());
Log.i(TAG,"RemoteService--savePerson:" + RemoteService.this.person);
}
};
}
在AndroidManifest.xml中定义RemoteService:
<service android:name=".RemoteService"
android:exported="true">
<intent-filter>
<action android:name="com.android.ACTION.RemoteService"></action>
</intent-filter>
</service>
特别注意,要在DemoAidlServer/app/build.gradle中,将aidl中定义的类配置进来,以防编译报找不到类的错误:
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java', 'src/main/aidl']
resources.srcDirs = ['src/main/java', 'src/main/aidl']
aidl.srcDirs = ['src/main/aidl']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
}
}
其完整代码为:
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.android.aidl.server"
minSdkVersion 28
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java', 'src/main/aidl']
resources.srcDirs = ['src/main/java', 'src/main/aidl']
aidl.srcDirs = ['src/main/aidl']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
客户端
这是我的客户端的代码结构:

将服务端的aidl文件复制到客户端
主要包括aidl文件,自定义的数据类型的java文件。(IRemoteService.aidl,Person.aidl,Rect.aidl,Person.java,Rect.java)
###2.在客户端调用aidl接口
MainActivity.java
package com.android.aidl.demoaidlclient;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
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 com.android.aidldemo.IMyAidlInterface;
import com.android.aidldemo.Person;
import com.android.aidldemo.Rect;
import android.os.Process;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private final static String TAG ="MainActivity";
private static final String BIND_SERVICE_ACTION = "com.android.ACTION.RemoteService";
private Button button_do;
private Button button_bind;
private Button button_unbind;
private IMyAidlInterface mIMyAidlInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
// TODO Auto-generated method stub
button_do = (Button)findViewById(R.id.button_do);
button_do.setOnClickListener(this);
button_bind = (Button)findViewById(R.id.button_bind);
button_bind.setOnClickListener(this);
button_unbind = (Button)findViewById(R.id.button_unbind);
button_unbind.setOnClickListener(this);
}
@Override
public void onClick(View view) {
// TODO Auto-generated method stub
if(view == button_do){
doAidlInterface();
}
if(view == button_bind){
//bindService();
bind();
}
if(view == button_unbind){
unBindSevice();
}
}
private void doAidlInterface() {
try {
Log.i(TAG, "mIMyAidlInterface.basicTypes");
mIMyAidlInterface.basicTypes(1,2,true,(float) 1.0,1.0,"test");
} catch (RemoteException e) {
e.printStackTrace();
}
try {
Log.i(TAG, "Process.myPid():" + Process.myPid());
Log.i(TAG, "mIMyAidlInterface.getPid():" + mIMyAidlInterface.getPid());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Log.i(TAG, "mIMyAidlInterface.onRemoteServiceDo()");
mIMyAidlInterface.onRemoteServiceDo();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Log.i(TAG, "mIMyAidlInterface.getRect()");
Log.i(TAG, "mIMyAidlInterface.getRect():" + mIMyAidlInterface.getRect());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Log.i(TAG, "mIMyAidlInterface.onProcessRect()");
mIMyAidlInterface.onProcessRect(new Rect(0,0,200,200));
} catch (RemoteException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
Log.i(TAG, "mIMyAidlInterface.getPerson()");
Log.i(TAG, "mIMyAidlInterface.getPerson():" + mIMyAidlInterface.getPerson());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Log.i(TAG, "mIMyAidlInterface.savePerson");
mIMyAidlInterface.savePerson(new Person(2,"name_2"));
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void bind() {
Log.d(TAG, "bind");
Intent intent = new Intent(BIND_SERVICE_ACTION);
intent.setComponent(new ComponentName("com.android.aidl.server", "com.android.aidl.server.RemoteService"));
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
startService(intent);
}
private void bindService() {
Intent serviceIntent = new Intent();
serviceIntent.setAction(BIND_SERVICE_ACTION);
serviceIntent.setComponent(new ComponentName("com.android.aidl.server", "com.android.aidl.server.RemoteService"));
final Intent eintent = new Intent(achieveExplicitFromImplicitIntent(this, serviceIntent));
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
Log.d(TAG, "bindService");
}
private void unBindSevice() {
Log.d(TAG, "unbindService");
if(mConnection != null){
try {
unbindService(mConnection);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unBindSevice();
}
public Intent achieveExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
Log.d(TAG,"packageName = " + packageName);
Log.d(TAG,"className = " + className);
ComponentName component = new ComponentName(packageName, className);
Intent explicitIntent = new Intent(implicitIntent);
explicitIntent.setComponent(component);
return explicitIntent;
}
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Following the example above for an AIDL interface,
// this gets an instance of the IRemoteInterface, which we can use to call on the service
mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "Service has unexpectedly disconnected");
mIMyAidlInterface = null;
}
};
}
布局文件为:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button_bind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_centerInParent="true"
android:text="bind service"
/>
<Button
android:id="@+id/button_do"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_below="@id/button_bind"
android:layout_centerInParent="true"
android:text="do" />
<Button
android:id="@+id/button_unbind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_below="@id/button_do"
android:layout_centerInParent="true"
android:text="unbind service" />
</RelativeLayout>
效果图为:

执行日志:
(1)点击bind service
17931 17931 D MainActivity: bind
(2)执行do操作
17931 17931 I MainActivity: mIMyAidlInterface.basicTypes
17290 17304 I RemoteService: RemoteService--basicTypes(1,2,true,1.0,1.0,test
17931 17931 I MainActivity: Process.myPid():17931
17290 17304 I RemoteService: RemoteService--getPid():17290
17931 17931 I MainActivity: mIMyAidlInterface.getPid():17290
17931 17931 I MainActivity: mIMyAidlInterface.onRemoteServiceDo()
17290 17304 I RemoteService: RemoteService--onRemoteServiceDo()
17931 17931 I MainActivity: mIMyAidlInterface.getRect()
17290 17304 I RemoteService: RemoteService--getRect():com.android.aidldemo.Rect@a7f6982--left:0--top:0--right:100--bottom:100
17931 17931 I MainActivity: mIMyAidlInterface.getRect():com.android.aidldemo.Rect@28d3eb7--left:0--top:0--right:100--bottom:100
17931 17931 I MainActivity: mIMyAidlInterface.onProcessRect()
17290 17304 I RemoteService: RemoteService--onProcessRect:com.android.aidldemo.Rect@a7f6982--left:0--top:0--right:200--bottom:200
17931 17931 I MainActivity: mIMyAidlInterface.getPerson()
17290 17304 I RemoteService: RemoteService--getPerson():com.android.aidldemo.Person@6f1b893--id:1--name:name_1
17931 17931 I MainActivity: mIMyAidlInterface.getPerson():com.android.aidldemo.Person@7c9a624--id:1--name:name_1
17931 17931 I MainActivity: mIMyAidlInterface.savePerson
17290 17304 I RemoteService: RemoteService--savePerson:com.android.aidldemo.Person@6f1b893--id:2--name:name_2

本文详细介绍如何使用AIDL实现Android平台上的跨进程通信。包括AIDL的基本概念、何时使用AIDL、AIDL的使用步骤及注意事项。通过一个具体示例,展示了服务端与客户端的代码实现过程。

被折叠的 条评论
为什么被折叠?



