一、Service 开启和停止
二、Service 执行耗时工作
三、IPC常用方式
四、AIDL(一)同一应用中使用AIDL及原理
五、AIDL(二)不同应用中使用、自定义数据类型及定向Tag
六、AIDL(三)实现回调
七、AIDL(四)获取服务及绑定和Binder传递流程
文章目录
AIDL(二)不同应用中使用、自定义数据类型及定向Tag
5.1 项目介绍
5.1.1 整体介绍
本项目中,因为探究的是不同应用中使用AIDL
、在AIDL
中自定义数据类型以及定向Tag
的使用,所以项目中有两个app
(分别为:AndroidIPCServer
:服务端、AndroidIPCClient
:客户端)、一个自定义数据类(VectorQuantity
),两个AIDL
文件(IVectorQuantityInterface
和VectorQuantity
)。
我们知道,AIDL
中在服务端和客户端之间会传递数据,但是传递的数据在双端却不是同一个对象,为确保两端对象修改的一致性,定义了定向Tag
,定向Tag
有三种,分别表示了在跨进程通信中数据的流向:
in
:其中in
表示数据只能由客户端流向服务端,表现为服务端将会接收到传递对象的完整数据,但是服务端对数据的修改不会传递到客户端;out
表示数据只能由服务端流向客户端,表现为服务端接收到的数据对象是空对象(由无参构造器创建),但是在服务端对数据的修改会传递到客户端;inout
表示数据可在服务端与客户端之间双向传递,表现为客户端传递到服务端的数据服务端可以接收到,服务端对数据的修改也可以传递到客户端;
5.1.2 定向Tag
实验
为验证in
、out
和inout
三个定向Tag
功能,我们可以定义一个自定义数据类VectorQuantity
,该类是一个一维向量,详细的内容参考后面的类代码。结合VectorQuantity
类和定向Tag
,设计出下面实验:
in tag
:在客户端数据为[1,2]
,随后服务端将数据修改为[11,12]
。根据理论结果,服务端接收到的数据为[1,2]
,但是修改的数据[11,12]
不能传递到客户端,所以,客户端数据仍为[1,2]
;our tag
:在客户端数据为[3,4]
,随后将数据修改为[13,14]
。根据理论结果,[3,4]
不能传递到服务端,服务端的数据为[]
,但是修改的数据[13,14]
可以传递到客户端,所以,客户端数据改变为[13,14]
;inout tag
:在客户端数据为[5,6]
,随后将数据修改为[15,16]
。根据理论结果,[5,6]
可以传递到服务端,服务端的数据为[5,6]
,修改的数据[13,14]
也可以传递到客户端,所以,客户端数据改变为[15,16]
;

5.2 项目代码
5.2.1 自定义数据类型
代码1
com.ieening.androidipcserver.vectorquantity.VectorQuantity
package com.ieening.androidipcserver.vectorquantity;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class VectorQuantity implements Parcelable { // 注释1
private static final String REGEX_PATTERN = "(?<=\\()( *?\\d+? *?,?)+?(?=\\))";
public ArrayList<Double> getComponents() {
return components;
}
public int getDimension() {
return components.size();
}
private final ArrayList<Double> components;
protected VectorQuantity(Parcel in) {
this();
for (double component :
Objects.requireNonNull(in.createDoubleArray())) {
this.components.add(component);
}
}
public VectorQuantity() { // 注释2
this.components = new ArrayList<>();
}
public static final Creator<VectorQuantity> CREATOR = new Creator<VectorQuantity>() { // 注释3
@Override
public VectorQuantity createFromParcel(Parcel in) {
return new VectorQuantity(in);
}
@Override
public VectorQuantity[] newArray(int size) {
return new VectorQuantity[size];
}
};
public VectorQuantity(ArrayList<Double> arrayList) {
this();
this.components.addAll(arrayList);
}
public static VectorQuantity getNewInstance(String componentsString) {
ArrayList<Double> doubles = getDoublesFromString(componentsString);
return new VectorQuantity(doubles);
}
@NonNull
private static ArrayList<Double> getDoublesFromString(String componentsString) {
String componentsStringTrim = componentsString.trim();
Matcher matcher = Pattern.compile(REGEX_PATTERN).matcher(componentsStringTrim);
ArrayList<Double> doubles = new ArrayList<>();
while (matcher.find()) {
int begin = matcher.start();
int end = matcher.end();
for (String component : componentsStringTrim.substring(begin, end).split(",")) {
doubles.add(Double.parseDouble(component.trim()));
}
}
return doubles;
}
@NonNull
@Override
public String toString() {
return this.components.toString();
}
@Override
public int describeContents() { // 注释4
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) { // 注释5
dest.writeDoubleArray(Arrays.stream(this.components.toArray()).mapToDouble(k -> (double) k).toArray());
}
public void update(String componentsString) {
ArrayList<Double> doubles = getDoublesFromString(componentsString);
this.components.clear();
this.components.addAll(doubles);
}
public void update(VectorQuantity vectorQuantity) {
this.components.clear();
this.components.addAll(vectorQuantity.getComponents());
}
public void readFromParcel(Parcel in) { // 注释6
this.components.clear();
for (double component :
Objects.requireNonNull(in.createDoubleArray())) {
this.components.add(component);
}
}
}
进行AIDL
通信时,需要对数据进行序列化,我们通过实现Parcelable
接口来实现序列化。
- 注释1:实现
Parcelable
接口; - 注释3、注释4、注释5:实现
Parcelable
接口中的方法; - 注释6:在
AIDL
中,如果需要支持out
和inout
定向标签,还要求添加readFromParcel
方法; - 注释2:需要有无参构造器,否则编译时会出错;
5.2.2 服务端代码
服务端代码结构如下:
5.3.2.1 aidl 文件
下面VectorQuantity.aidl
文件,定义VectorQuantity parcelable
对象,以供其他AIDL
文件使用。
代码2
com/ieening/androidipcserver/vectorquantity/VectorQuantity.aidl
// VectorQuantity.aidl
package com.ieening.androidipcserver.vectorquantity;
// Declare any non-default types here with import statements
parcelable VectorQuantity;
代码3
com/ieening/androidipcserver/vectorquantity/IVectorQuantityInterface.aidl
// IVectorQuantityInterface.aidl
package com.ieening.androidipcserver.vectorquantity;
// Declare any non-default types here with import statements
import com.ieening.androidipcserver.vectorquantity.VectorQuantity; // 注释1
interface IVectorQuantityInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void updateVectorQuantityIn(in VectorQuantity vectorQuantity); // 注释2
void updateVectorQuantityOut(out VectorQuantity vectorQuantity); // 注释3
void updateVectorQuantityInOut(inout VectorQuantity vectorQuantity); // 注释4
}
- 注释1:导入
VectorQuantity parcelable
对象; - 注释2:定义
updateVectorQuantityIn
方法,注意参数使用in
修饰; - 注释3:定义
updateVectorQuantityOut
方法,注意参数使用out
修饰; - 注释4:定义
updateVectorQuantityInOut
方法,注意参数使用inout
修饰;
5.2.2.2 Service 代码
代码4
com.ieening.androidipcserver.vectorquantity.VectorQuantityService
package com.ieening.androidipcserver.vectorquantity;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.ieening.androidipcserver.MainActivity;
public class VectorQuantityService extends Service {
private final static String TAG = VectorQuantityService.class.getName();
public static final String UPDATE_EDIT_TEXT_ACTION = "action_update_receive_from_client_edit_text";
private final IVectorQuantityInterface.Stub iVectorQuantityBinder = new IVectorQuantityInterface.Stub() { // 注释1
@Override
public void updateVectorQuantityIn(VectorQuantity vectorQuantity) {
sendBroadcastToActivity(vectorQuantity, 1);
Log.d(TAG, "receive from client updateVectorQuantityIn firstVectorQuantity = " + vectorQuantity);
VectorQuantity newInstance = VectorQuantity.getNewInstance(MainActivity.firstVectorQuantityString);
if (newInstance.getDimension() > 0) {
vectorQuantity.update(newInstance);
Log.d(TAG, "send to client updateVectorQuantityIn firstVectorQuantity = " + vectorQuantity);
}
}
@Override
public void updateVectorQuantityOut(VectorQuantity vectorQuantity) {
sendBroadcastToActivity(vectorQuantity, 2);
Log.d(TAG, "receive from client updateVectorQuantityOut secondVectorQuantity = " + vectorQuantity);
VectorQuantity newInstance = VectorQuantity.getNewInstance(MainActivity.secondVectorQuantityString);
if (newInstance.getDimension() > 0) {
vectorQuantity.update(newInstance);
Log.d(TAG, "send to client updateVectorQuantityOut secondVectorQuantity = " + vectorQuantity);
}
}
@Override
public void updateVectorQuantityInOut(VectorQuantity vectorQuantity) {
sendBroadcastToActivity(vectorQuantity, 3);
Log.d(TAG, "receive from client updateVectorQuantityOut thirdVectorQuantity = " + vectorQuantity);
VectorQuantity newInstance = VectorQuantity.getNewInstance(MainActivity.thirdVectorQuantityString);
if (newInstance.getDimension() > 0) {
vectorQuantity.update(newInstance);
Log.d(TAG, "send to client updateVectorQuantityOut thirdVectorQuantity = " + vectorQuantity);
}
}
};
private void sendBroadcastToActivity(VectorQuantity vectorQuantity, int number) { // 注释3
Intent activity_intent = new Intent(UPDATE_EDIT_TEXT_ACTION);
activity_intent.putExtra("number", number);
activity_intent.putExtra("vector_quantity", vectorQuantity);
activity_intent.setPackage(getPackageName());
sendBroadcast(activity_intent);
}
public VectorQuantityService() {
}
@Override
public IBinder onBind(Intent intent) { // 注释2
// TODO: Return the communication channel to the service.
return iVectorQuantityBinder;
}
}
- 注释1:
IVectorQuantityInterface.Stub()
实现Stub
代码,里面的操作是将客户端传过来的数据通过broadcast
传给服务端MainActivity
展现,然后进行修改; - 注释2:返回服务端
Ibinder
; - 注释3:将客户端发送过来的数据通过
Broadcast
传递给MainActivity
;
5.2.2.3 MainActivity 代码
5.2.3 客户端代码
客户端代码结构如下:
5.2.3.1 aidl 文件和自定义数据类代码
aidl
文件和自定义数据类代码可以完全复制服务端代码,包括包名。
5.2.3.2 客户端调用aidl
接口文件中定义的方法
代码5
com.ieening.androidipcclient.MainActivity
package com.ieening.androidipcclient;
......
import com.ieening.androidipcserver.vectorquantity.IVectorQuantityInterface;
import com.ieening.androidipcserver.vectorquantity.VectorQuantity;
public class MainActivity extends AppCompatActivity {
private final static String TAG = MainActivity.class.getName();
private ActivityMainBinding binding;
private IVectorQuantityInterface vectorQuantityRemote = null;
private final VectorQuantity firstVectorQuantity = new VectorQuantity(); // 注释1
private final VectorQuantity secondVectorQuantity = new VectorQuantity();
private final VectorQuantity thirdVectorQuantity = new VectorQuantity();
private final ServiceConnection serviceConnection = new ServiceConnection() { // 注释2
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
vectorQuantityRemote = IVectorQuantityInterface.Stub.asInterface(service);
Log.d(TAG, "executing serviceConnection onServiceConnected");
changeVectorQuantityButtonsStatus();
}
@Override
public void onServiceDisconnected(ComponentName name) {
vectorQuantityRemote = null;
Log.d(TAG, "executing serviceConnection onServiceDisconnected");
changeVectorQuantityButtonsStatus();
}
};
......
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
......
setVectorQuantityNumberButtonsOnclickListener();
......
}
......
private void setVectorQuantityNumberButtonsOnclickListener() { // 注释3
binding.vectorQuantityFirstNumberButton.setOnClickListener(v -> {
try {
Log.d(TAG, "send to server updateVectorQuantityIn firstVectorQuantity = " + firstVectorQuantity);
vectorQuantityRemote.updateVectorQuantityIn(firstVectorQuantity);
binding.firstNumberReceiveFromServerEditText.setText(firstVectorQuantity.toString());
Log.d(TAG, "receive from server updateVectorQuantityIn firstVectorQuantity = " + firstVectorQuantity);
} catch (RemoteException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
});
binding.vectorQuantitySecondNumberButton.setOnClickListener(v -> {
try {
Log.d(TAG, "send to server updateVectorQuantityOut secondVectorQuantity = " + secondVectorQuantity);
vectorQuantityRemote.updateVectorQuantityOut(secondVectorQuantity);
binding.secondNumberReceiveFromServerEditText.setText(secondVectorQuantity.toString());
Log.d(TAG, "receive from server updateVectorQuantityOut secondVectorQuantity = " + secondVectorQuantity);
} catch (RemoteException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
});
binding.vectorQuantityThirdNumberButton.setOnClickListener(v -> {
try {
Log.d(TAG, "send to server updateVectorQuantityInOut thirdVectorQuantity = " + thirdVectorQuantity);
vectorQuantityRemote.updateVectorQuantityInOut(thirdVectorQuantity);
binding.thirdNumberReceiveFromServerEditText.setText(thirdVectorQuantity.toString());
Log.d(TAG, "receive from server updateVectorQuantityInOut thirdVectorQuantity = " + thirdVectorQuantity);
} catch (RemoteException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
});
}
......
}
- 注释1:三个定向
Tag
在客户端对应的数据对象; - 注释2:绑定服务端
Service
的ServiceConnection
类; - 注释3:调用
aidl
接口中的三个方法,将数据传递给服务端,并接收服务端传递过来的数据;
5.3 结果展示
5.3.1 软件界面介绍
5.3.2 操作结果
从结果上看,完全符合4.1.2
中预设的实验现象。
5.4 数据流实现细节
AIDL
文件最终生成.java
文件,因此需要在该文件里找答案。
代码6
com.ieening.androidipcserver.vectorquantity.IVectorQuantityInterface
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.ieening.androidipcserver.vectorquantity;
public interface IVectorQuantityInterface extends android.os.IInterface
{
......
private static class Proxy implements com.ieening.androidipcserver.vectorquantity.IVectorQuantityInterface
{
......
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override public void updateVectorQuantityIn(com.ieening.androidipcserver.vectorquantity.VectorQuantity vectorQuantity) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_Parcel.writeTypedObject(_data, vectorQuantity, 0);
boolean _status = mRemote.transact(Stub.TRANSACTION_updateVectorQuantityIn, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void updateVectorQuantityOut(com.ieening.androidipcserver.vectorquantity.VectorQuantity vectorQuantity) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_updateVectorQuantityOut, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
vectorQuantity.readFromParcel(_reply);
}
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void updateVectorQuantityInOut(com.ieening.androidipcserver.vectorquantity.VectorQuantity vectorQuantity) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_Parcel.writeTypedObject(_data, vectorQuantity, 0);
boolean _status = mRemote.transact(Stub.TRANSACTION_updateVectorQuantityInOut, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
vectorQuantity.readFromParcel(_reply);
}
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
......
}
......
/** @hide */
static class _Parcel {
static private <T> T readTypedObject(
android.os.Parcel parcel,
android.os.Parcelable.Creator<T> c) {
if (parcel.readInt() != 0) {
return c.createFromParcel(parcel);
} else {
return null;
}
}
static private <T extends android.os.Parcelable> void writeTypedObject(
android.os.Parcel parcel, T value, int parcelableFlags) {
if (value != null) {
parcel.writeInt(1);
value.writeToParcel(parcel, parcelableFlags);
} else {
parcel.writeInt(0);
}
}
}
}
如上代码所示,在Proxy
中,
- 用
in
修饰的updateVectorQuantityIn
函数中,在执行mRemote.transact
之前,会将数据写入(_Parcel.writeTypedObject(_data, vectorQuantity, 0)
),但没有将数据读出(vectorQuantity.readFromParcel(_reply)
); - 用
out
修饰的updateVectorQuantityOut
函数中,在执行mRemote.transact
之前,不会将数据写入(_Parcel.writeTypedObject(_data, vectorQuantity, 0)
),但会将数据读出(vectorQuantity.readFromParcel(_reply)
); - 用
inout
修饰的updateVectorQuantityInOut
函数中,在执行mRemote.transact
之前,既有将数据写入(_Parcel.writeTypedObject(_data, vectorQuantity, 0)
),也有将数据读出(vectorQuantity.readFromParcel(_reply)
);