Skip to content

Commit b709736

Browse files
wintmainwosys
authored andcommitted
[foundation][feat]Add AIDL sample
1 parent bcad659 commit b709736

File tree

8 files changed

+271
-3
lines changed

8 files changed

+271
-3
lines changed

app-catalog/samples/foundation/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ android {
1212
}
1313
buildFeatures {
1414
viewBinding = true
15+
aidl = true
1516
}
1617
namespace 'com.wintmain.foundation'
1718
}

app-catalog/samples/foundation/src/main/AndroidManifest.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,12 @@
352352
<action android:name="com.android.MY_BROADCAST_EXT" />
353353
</intent-filter>
354354
</receiver>
355+
356+
<service
357+
android:name=".PeopleRemoteService"
358+
android:process=":remote"
359+
android:enabled="true"
360+
android:exported="true" />
355361
</application>
356362

357363
</manifest>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// INewPeopleListener.aidl
2+
package com.wintmain.foundation;
3+
4+
import com.wintmain.foundation.People;
5+
6+
// AIDL中无法使用普通接口,所以创建此文件
7+
8+
interface INewPeopleListener {
9+
void onNewPeople(in People newPeople);
10+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// IPeopleManager.aidl
2+
// AIDL接口中只支持方法,不支持声明静态常量
3+
package com.wintmain.foundation;
4+
5+
// 自定义的Parcelable对象和AIDL对象不管是否和当前的AIDL文件位于同一个包内,也必须要显式import进来
6+
7+
import com.wintmain.foundation.People;
8+
import com.wintmain.foundation.INewPeopleListener;
9+
10+
interface IPeopleManager {
11+
List<People> getPeopleList();
12+
// addPeople方法的参数中有in关键字,因为aidl中除了基本数据类型,其它类型的参数必须标上方向:in、out或者inout,
13+
// 我们需根据实现需要去指定参数类型,因为这在底层实现是有开销的。
14+
void addPeople(in People people);
15+
16+
// 扩展新增代码:新增接口
17+
void registerListener(INewPeopleListener listener);
18+
void unregisterListener(INewPeopleListener listener);
19+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// People.aidl
2+
package com.wintmain.foundation;
3+
4+
// Declare any non-default types here with import statements
5+
6+
// 在Android的AIDL中,仅支持的数据类型有:
7+
// 1. 基本数据类型(int、long、char、boolean、double等)
8+
// 2. String和CharSequence
9+
// 3. List:只支持ArrayList,里面的每个元素都必须能够被AIDL支持
10+
// 4. Map:只支持HashMap,里面的每个元素都必须能够被AIDL支持
11+
// 5. Parcelable:所有实现了Parcelable接口的对象
12+
// 6. AIDL:所有的AIDL接口本身也可以在AIDL文件中使用
13+
14+
// Parcelable的作用是序列化对象,因为跨进程通信传输对象必须是以序列化和反序列化的方式进行。
15+
// Parcelable的实现有些繁琐,但性能效率很高。
16+
17+
import com.wintmain.foundation.People;
18+
19+
// People should be declared in a file called com/wintmain/foundation/People.aidl
20+
parcelable People;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2023-2025 wintmain
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.wintmain.foundation;
18+
19+
import android.os.Parcel;
20+
import android.os.Parcelable;
21+
import androidx.annotation.NonNull;
22+
23+
public class People implements Parcelable {
24+
25+
public int pId;
26+
public String pName;
27+
28+
public People(Parcel in) {
29+
pId = in.readInt();
30+
pName = in.readString();
31+
}
32+
33+
public People(int pId, String pName) {
34+
this.pId = pId;
35+
this.pName = pName;
36+
}
37+
38+
public String getName() {
39+
return pName;
40+
}
41+
42+
public void setName(String pName) {
43+
this.pName = pName;
44+
}
45+
46+
public int getId() {
47+
return pId;
48+
}
49+
50+
public void setId(int pId) {
51+
this.pId = pId;
52+
}
53+
54+
// 内容描述功能由describeContents方法来完成
55+
// 几乎在所有情况下这方法都应该返回0,仅当当前对象中存在文件描述符时才返回1。
56+
@Override
57+
public int describeContents() {
58+
return 0;
59+
}
60+
61+
// 序列化功能由writeToParcel方法来完成,最终是通过Parcel中的一系列write方法来完成的。
62+
@Override
63+
public void writeToParcel(@NonNull Parcel dest, int flags) {
64+
dest.writeInt(pId);
65+
dest.writeString(pName);
66+
}
67+
68+
// 反序列化功能由CREATOR来完成,其内部标明了如何创建序列化对象和数组,
69+
// 并通过Parcel的一系列read方法来完成反序列化过程。
70+
public static final Parcelable.Creator<People> CREATOR = new Parcelable.Creator<>() {
71+
public People createFromParcel(Parcel in) {
72+
return new People(in);
73+
}
74+
75+
public People[] newArray(int size) {
76+
return new People[size];
77+
}
78+
};
79+
80+
81+
@NonNull
82+
@Override
83+
public String toString() {
84+
return String.format("pId:%s, pName:%s", pId, pName);
85+
}
86+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2023-2025 wintmain
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.wintmain.foundation
18+
19+
import android.app.Service
20+
import android.content.Intent
21+
import android.os.Binder
22+
import android.os.IBinder
23+
import android.os.RemoteCallbackList
24+
import java.util.concurrent.CopyOnWriteArrayList
25+
26+
// 服务端代码,客户端见[PlaceHoldActivity.java]
27+
class PeopleRemoteService : Service() {
28+
val mPeopleList = CopyOnWriteArrayList<People>()
29+
// 客户端注册和移除注册过程中使用的虽是同一个客户端对象,
30+
// 但通过Binder传递到服务端后,产生了两个不同的对象。
31+
// 因为对象是不能跨进程直接传输的,对象的跨进程传输本质上都是反序列化的过程
32+
val mListenList = RemoteCallbackList<INewPeopleListener>()
33+
34+
private val mBinder: Binder = object : IPeopleManager.Stub() {
35+
override fun getPeopleList(): List<People> {
36+
return mPeopleList
37+
}
38+
39+
override fun addPeople(people: People) {
40+
mPeopleList.add(people)
41+
42+
// 扩展新增代码:新加对象后执行监听回调
43+
for (i in 0 until mListenList.beginBroadcast()) {
44+
val listener: INewPeopleListener = mListenList.getBroadcastItem(i)
45+
listener.onNewPeople(people)
46+
}
47+
mListenList.finishBroadcast()
48+
}
49+
50+
// RemoteCallbackList是系统专门提供的用于删除跨进程listener接口,它是一个泛型,支持管理任意AIDL接口。
51+
// 另外它内部自动实现了线程同步的功能。
52+
// beginBroadcast和finishBroadcast必须要配对使用,哪怕仅仅获取RemoteCallbackList中的元素个数
53+
override fun registerListener(listener: INewPeopleListener) {
54+
mListenList.beginBroadcast()
55+
mListenList.register(listener)
56+
mListenList.finishBroadcast()
57+
}
58+
59+
override fun unregisterListener(listener: INewPeopleListener) {
60+
mListenList.beginBroadcast()
61+
mListenList.unregister(listener)
62+
mListenList.finishBroadcast()
63+
}
64+
}
65+
66+
override fun onBind(intent: Intent): IBinder {
67+
return mBinder
68+
}
69+
}

app-catalog/samples/foundation/src/main/java/com/wintmain/foundation/PlaceHolderActivity.java

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
import android.content.ComponentName;
2121
import android.content.Context;
2222
import android.content.Intent;
23+
import android.content.ServiceConnection;
2324
import android.os.Bundle;
25+
import android.os.IBinder;
26+
import android.os.RemoteException;
2427
import android.provider.AlarmClock;
2528
import android.widget.TextView;
2629
import androidx.appcompat.app.AppCompatActivity;
@@ -36,12 +39,19 @@
3639
description = "一个为了测试API调用的入口",
3740
tags = "A-Self_demos")
3841
public class PlaceHolderActivity extends AppCompatActivity {
42+
private static final String TAG = PlaceHolderActivity.class.getSimpleName();
43+
IPeopleManager peopleManager;
3944

4045
@Override
4146
protected void onCreate(Bundle savedInstanceState) {
4247
super.onCreate(savedInstanceState);
4348
setContentView(R.layout.pft_activity_main);
4449

50+
// AIDL示例 S
51+
Intent intent = new Intent(this, PeopleRemoteService.class);
52+
bindService(intent, mConnection, BIND_AUTO_CREATE);
53+
// AIDL示例 E
54+
4555
// 初始化一些三方库
4656
initLibs(getApplication());
4757

@@ -62,9 +72,12 @@ public void onTitleClick(TitleBarExt titleBar) {
6272
newIntent.setAction(AlarmClock.ACTION_SET_ALARM);
6373
newIntent.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
6474
newIntent.setComponent(new ComponentName("com.android.deskclock", "com.android.deskclock.HandleApiCalls"));
65-
startActivity(newIntent);
66-
67-
ToastUtils.show("你点击了中间,并且新建了一个9:30的闹钟");
75+
try {
76+
startActivity(newIntent);
77+
ToastUtils.show("你点击了中间,并且新建了一个9:30的闹钟");
78+
} catch (Exception e) {
79+
ToastUtils.show("你点击了中间,但是新建闹钟失败");
80+
}
6881
}
6982

7083
@Override
@@ -74,6 +87,20 @@ public void onRightClick(TitleBarExt titleBar) {
7487
});
7588
}
7689

90+
@Override
91+
protected void onDestroy() {
92+
// 移除监听
93+
if (peopleManager != null && peopleManager.asBinder().isBinderAlive()) {
94+
try {
95+
peopleManager.unregisterListener(mNewPeopleListener);
96+
} catch (RemoteException e) {
97+
android.util.Log.d(TAG, "catch:" + e.getMessage());
98+
}
99+
}
100+
unbindService(mConnection);
101+
super.onDestroy();
102+
}
103+
77104
private void initLibs(Application application) {
78105
// 初始化 TitleBar 默认样式
79106
TitleBarExt.setDefaultStyle(
@@ -97,4 +124,34 @@ public TextView newRightView(Context context) {
97124
// 初始化 Toast
98125
ToastUtils.init(this.getApplication());
99126
}
127+
128+
129+
private final ServiceConnection mConnection = new ServiceConnection() {
130+
public void onServiceConnected(ComponentName className, IBinder service) {
131+
android.util.Log.d(TAG, "onServiceConnected...");
132+
peopleManager = IPeopleManager.Stub.asInterface(service);
133+
try {
134+
People people = new People(1000, "wintmain");
135+
// 注册监听
136+
peopleManager.registerListener(mNewPeopleListener);
137+
peopleManager.addPeople(people);
138+
} catch (RemoteException e) {
139+
android.util.Log.d(TAG, "catch:" + e.getMessage());
140+
}
141+
}
142+
public void onServiceDisconnected(ComponentName className) {
143+
android.util.Log.d(TAG, "onServiceDisconnected!!!");
144+
ToastUtils.show("onServiceDisconnected!!!");
145+
peopleManager = null;
146+
}
147+
};
148+
149+
150+
// 定义监听接口
151+
private final INewPeopleListener mNewPeopleListener = new INewPeopleListener.Stub() {
152+
@Override
153+
public void onNewPeople(People newPeople) {
154+
ToastUtils.show("onNewPeople: " + newPeople);
155+
}
156+
};
100157
}

0 commit comments

Comments
 (0)