Android初学 IPC机制(Android IPC Mechanisms)【翻译】
Android 接口定义语言 (AIDL)
参考资源:AIDL使用详解及原理
感觉和Web开发中的RPC(远程过程调用)有点像
实现:Client APP将出生年月传入Server APP,在Server APP中计算年龄并返回给Client APP
第一步,写Server APP
创建 .aidl
文件
声明JavaBean
// MyBirthdayAndAge.aidl
parcelable MyBirthdayAndAge;
声明接口
// IMyAidlInterface.aidl
interface IMyAidlInterface {
int add(int a, int b);
}
结构图
创建完成之后,需要编译项目
生产对应的java代码,否则不会有提示。
写对应实体类、在Service中实现接口
实体类
public class MyBirthdayAndAge implements Parcelable {
private String birthday;
private int age;
public MyBirthdayAndAge(Parcel source) {
birthday = source.readString();
age = source.readInt();
}
// getter, setter method...
@Override
public int describeContents() {
return 0;
}
public void readFromParcel(Parcel dest) {
birthday = dest.readString();
age = dest.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(birthday);
dest.writeInt(age);
}
public MyBirthdayAndAge() {
}
public static final Creator<MyBirthdayAndAge> CREATOR = new Creator<MyBirthdayAndAge>() {
@Override
public MyBirthdayAndAge createFromParcel(Parcel source) {
return new MyBirthdayAndAge(source);
}
@Override
public MyBirthdayAndAge[] newArray(int size) {
return new MyBirthdayAndAge[size];
}
};
@Override
public String toString() {
return "MyBirthdayAndAge{" +
"birthday=" + birthday +
", age=" + age +
'}';
}
}
写Service并实现接口
public class GetAgeService extends Service {
public GetAgeService() {
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
private IBinder binder = new ICalculateAge.Stub() {
@Override
public MyBirthdayAndAge getAge(MyBirthdayAndAge myBirthdayAndAge) throws RemoteException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
Date parse = format.parse(myBirthdayAndAge.getBirthday());
int age = new Date().getYear() - parse.getYear();
myBirthdayAndAge.setAge(age);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(myBirthdayAndAge);
return myBirthdayAndAge;
}
};
}
在清单文件
(Manifest.xml)中暴露此Service
<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/AppTheme">
<service
android:name=".GetAgeService"
android:enabled="true"
android:exported="true"/>
</application>
当客户端(如 Activity)调用 bindService() 以连接此服务时,客户端的 onServiceConnected() 回调会接收服务的 onBind() 方法所返回的 binder 实例。
Server的项目结构如下图所示:
第二步,写Client APP
创建新工程Client APP,将Server APP中的aidl
文件夹原封不动的移动到Client APP下
此时Client APP
的项目结构如下图所示:
此时编译项目会提示在com.thundersoft.ipcserver
下找不到 MyBirthdayAndAge
这个实体类,所以我们需要创建一个包com.thundersoft.ipcserver
,然后将Server APP中对应的实体类复制过来。此时的项目结构如下图所示。
在MainActivity中绑定Service并创建点击事件调用方法
public class MainActivity extends AppCompatActivity {
private ICalculateAge calculateAge;
private static final String TAG = "ASDL";
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
calculateAge = ICalculateAge.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
calculateAge = null;
}
};
private void bindService() {
Intent intent1 = new Intent();
intent1.setComponent(new ComponentName("com.thundersoft.ipcserver",
"com.thundersoft.ipcserver.GetAgeService"));
bindService(intent1, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService();
}
public void getAge(View view) {
MyBirthdayAndAge birthdayAndAge = new MyBirthdayAndAge();
birthdayAndAge.setBirthday("1998-09-12");
try {
MyBirthdayAndAge age = calculateAge.getAge(birthdayAndAge);
Log.i(TAG, "getAge: " + age);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
对应布局文件aactivity_main.xml
:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="getAge"
android:textSize="40sp"
android:onClick="getAge" />
</androidx.constraintlayout.widget.ConstraintLayout>
点击TextView
时,客户端会打印如下log
2021-07-22 08:48:03.040 12665-12665/com.thundersoft.ipcclient I/ASDL: getAge: MyBirthdayAndAge{birthday=1998-09-12, age=23}
服务端会打印如下log
2021-07-22 08:48:03.038 12595-12607/com.thundersoft.ipcserver I/System.out: MyBirthdayAndAge{birthday=1998-09-12, age=23}
结束Peace!
这个demo可以在Android 9上运行,11好像不行。
先启动Server再启动Client。