两层架构:
- 内部 `RegistrantList` 用于框架内快速同步通知
- 外部 `TelephonyRegistry` 用于应用层跨进程异步通知
Android Telephony 监听注册机制详解
Android Telephony 框架使用了一套优雅且高效的观察者模式实现,通过 Registrant 和 RegistrantList 提供了强大的事件通知机制。这是整个电信框架内部通信的基石。
一、核心类设计
1. Registrant (单个注册者)
public class Registrant
{
@UnsupportedAppUsage
public
Registrant(Handler h, int what, Object obj)
{
refH = new WeakReference(h);
this.what = what;
userObj = obj;
}
@UnsupportedAppUsage
public void
clear()
{
refH = null;
userObj = null;
}
@UnsupportedAppUsage
public void
notifyRegistrant()
{
internalNotifyRegistrant (null, null);
}
@UnsupportedAppUsage
public void
notifyResult(Object result)
{
internalNotifyRegistrant (result, null);
}
public void
notifyException(Throwable exception)
{
internalNotifyRegistrant (null, exception);
}
/**
* This makes a copy of @param ar
*/
@UnsupportedAppUsage
public void
notifyRegistrant(AsyncResult ar)
{
internalNotifyRegistrant (ar.result, ar.exception);
}
/*package*/ void
internalNotifyRegistrant (Object result, Throwable exception)
{
Handler h = getHandler();
if (h == null) {
clear();
} else {
Message msg = Message.obtain();
msg.what = what;
msg.obj = new AsyncResult(userObj, result, exception);
h.sendMessage(msg);
}
}
/**
* NOTE: May return null if weak reference has been collected
*/
@UnsupportedAppUsage
public Message
messageForRegistrant()
{
Handler h = getHandler();
if (h == null) {
clear();
return null;
} else {
Message msg = h.obtainMessage();
msg.what = what;
msg.obj = userObj;
return msg;
}
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public Handler
getHandler()
{
if (refH == null)
return null;
return (Handler) refH.get();
}
WeakReference refH;
int what;
Object userObj;
}
关键特性:
-
弱引用 Handler
WeakReference refH;- 避免内存泄漏
- 如果 Handler 所属的对象被回收,自动失效
-
三要素:
refH: Handler 的弱引用what: 消息类型码(Message.what)userObj: 用户自定义对象
-
通知机制:
msg.what = what; msg.obj = new AsyncResult(userObj, result, exception); h.sendMessage(msg);- 构造
Message,封装AsyncResult - 通过 Handler 发送到目标线程
- 构造
2. RegistrantList (注册者列表)
public class RegistrantList
{
ArrayList registrants = new ArrayList(); // of Registrant
@UnsupportedAppUsage
public RegistrantList() {
}
@UnsupportedAppUsage
public synchronized void
add(Handler h, int what, Object obj)
{
add(new Registrant(h, what, obj));
}
@UnsupportedAppUsage
public synchronized void
addUnique(Handler h, int what, Object obj)
{
// if the handler is already in the registrant list, remove it
remove(h);
add(new Registrant(h, what, obj));
}
@UnsupportedAppUsage
public synchronized void
add(Registrant r)
{
removeCleared();
registrants.add(r);
}
@UnsupportedAppUsage
public synchronized void
removeCleared()
{
for (int i = registrants.size() - 1; i >= 0 ; i--) {
Registrant r = (Registrant) registrants.get(i);
if (r.refH == null) {
registrants.remove(i);
}
}
}
public synchronized void removeAll() {
registrants.clear();
}
@UnsupportedAppUsage
public synchronized int
size()
{
return registrants.size();
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public synchronized Object
get(int index)
{
return registrants.get(index);
}
private synchronized void
internalNotifyRegistrants (Object result, Throwable exception)
{
for (int i = 0, s = registrants.size(); i < s ; i++) {
Registrant r = (Registrant) registrants.get(i);
r.internalNotifyRegistrant(result, exception);
}
}
@UnsupportedAppUsage
public /*synchronized*/ void
notifyRegistrants()
{
internalNotifyRegistrants(null, null);
}
public /*synchronized*/ void
notifyException(Throwable exception)
{
internalNotifyRegistrants (null, exception);
}
@UnsupportedAppUsage
public /*synchronized*/ void
notifyResult(Object result)
{
internalNotifyRegistrants (result, null);
}
@UnsupportedAppUsage
public /*synchronized*/ void
notifyRegistrants(AsyncResult ar)
{
internalNotifyRegistrants(ar.result, ar.exception);
}
@UnsupportedAppUsage
public synchronized void
remove(Handler h)
{
for (int i = 0, s = registrants.size() ; i < s ; i++) {
Registrant r = (Registrant) registrants.get(i);
Handler rh;
rh = r.getHandler();
/* Clean up both the requested registrant and
* any now-collected registrants
*/
if (rh == null || rh == h) {
r.clear();
}
}
removeCleared();
}
}
关键方法:
-
add() vs addUnique()
add(): 允许同一 Handler 多次注册addUnique(): 先移除已存在的,确保唯一性
-
removeCleared()
- 清理已失效的 Registrant (WeakReference 被回收)
- 自动垃圾清理机制
-
notifyRegistrants()
- 遍历所有注册者
- 逐个通知
二、典型使用模式
1. 声明 RegistrantList
protected final RegistrantList mPreciseCallStateRegistrants = new RegistrantList();
private final RegistrantList mHandoverRegistrants = new RegistrantList();
private final RegistrantList mNewRingingConnectionRegistrants = new RegistrantList();
private final RegistrantList mIncomingRingRegistrants = new RegistrantList();
protected final RegistrantList mDisconnectRegistrants = new RegistrantList();
private final RegistrantList mServiceStateRegistrants = new RegistrantList();
protected final RegistrantList mMmiCompleteRegistrants = new RegistrantList();
@UnsupportedAppUsage
protected final RegistrantList mMmiRegistrants = new RegistrantList();
protected final RegistrantList mUnknownConnectionRegistrants = new RegistrantList();
protected final RegistrantList mSuppServiceFailedRegistrants = new RegistrantList();
protected final RegistrantList mRadioOffOrNotAvailableRegistrants = new RegistrantList();
protected final RegistrantList mSimRecordsLoadedRegistrants = new RegistrantList();
private final RegistrantList mVideoCapabilityChangedRegistrants = new RegistrantList();
protected final RegistrantList mEmergencyCallToggledRegistrants = new RegistrantList();
private final RegistrantList mCellInfoRegistrants = new RegistrantList();
private final RegistrantList mRedialRegistrants = new RegistrantList();
private final RegistrantList mPhysicalChannelConfigRegistrants = new RegistrantList();
private final RegistrantList mOtaspRegistrants = new RegistrantList();
private final RegistrantList mPreferredNetworkTypeRegistrants = new RegistrantList();
Phone 类中的典型 RegistrantList:
- 服务状态变化
- 来电通知
- 连接断开
- MMI 命令
- 信号强度
- 小区信息
- ...
2. 注册接口
public void registerForVoiceRoamingOn(Handler h, int what, Object obj) {
Registrant r = new Registrant(h, what, obj);
mVoiceRoamingOnRegistrants.add(r);
if (mSS.getVoiceRoaming()) {
r.notifyRegistrant();
}
}
public void unregisterForVoiceRoamingOn(Handler h) {
mVoiceRoamingOnRegistrants.remove(h);
}
/**
* Registration point for roaming off of mobile voice
* combined roaming is true when roaming is true and ONS differs SPN
*
* @param h handler to notify
* @param what what code of message when delivered
* @param obj placed in Message.obj
*/
public void registerForVoiceRoamingOff(Handler h, int what, Object obj) {
Registrant r = new Registrant(h, what, obj);
mVoiceRoamingOffRegistrants.add(r);
if (!mSS.getVoiceRoaming()) {
r.notifyRegistrant();
}
}
标准模式:
public void registerForXxxChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant(h, what, obj);
mXxxRegistrants.add(r);
// 立即通知当前状态(可选)
if (currentState满足条件) {
r.notifyRegistrant();
}
}
public void unregisterForXxxChanged(Handler h) {
mXxxRegistrants.remove(h);
}
3. 触发通知
private void notifyCdmaSubscriptionInfoReady() {
if (mCdmaForSubscriptionInfoReadyRegistrants != null) {
if (DBG) log("CDMA_SUBSCRIPTION: call notifyRegistrants()");
mCdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants();
}
}
通知方式:
-
无参数通知:
mRegistrants.notifyRegistrants(); -
携带结果:
mRegistrants.notifyResult(result); -
携带 AsyncResult:
AsyncResult ar = new AsyncResult(null, result, exception); mRegistrants.notifyRegistrants(ar);
三、完整示例:网络驻网状态监听
1. 定义 RegistrantList (ServiceStateTracker)
private final RegistrantList mNetworkAttachedRegistrants = new RegistrantList();
private final RegistrantList mNetworkDetachedRegistrants = new RegistrantList();
2. 提供注册接口
public void registerForNetworkAttached(Handler h, int what, Object obj) {
Registrant r = new Registrant(h, what, obj);
mNetworkAttachedRegistrants.add(r);
if (mSS.getState() == ServiceState.STATE_IN_SERVICE) {
r.notifyRegistrant();
}
}
public void unregisterForNetworkAttached(Handler h) {
mNetworkAttachedRegistrants.remove(h);
}
/**
* Registration point for transition into network detached.
* @param h handler to notify
* @param what what code of message when delivered
* @param obj in Message.obj
*/
public void registerForNetworkDetached(Handler h, int what, Object obj) {
Registrant r = new Registrant(h, what, obj);
mNetworkDetachedRegistrants.add(r);
if (mSS.getState() != ServiceState.STATE_IN_SERVICE) {
r.notifyRegistrant();
}
}
public void unregisterForNetworkDetached(Handler h) {
mNetworkDetachedRegistrants.remove(h);
}
特点: 注册时立即检查当前状态,如果已满足条件则立即通知
3. 监听者注册 (示例:DisplayInfoController)
// DisplayInfoController.java
private static final int EVENT_SERVICE_STATE_CHANGED = 1;
public DisplayInfoController(Phone phone) {
mPhone = phone;
// 注册服务状态变化监听
mPhone.getServiceStateTracker()
.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_SERVICE_STATE_CHANGED:
AsyncResult ar = (AsyncResult) msg.obj;
ServiceState ss = (ServiceState) ar.result;
// 处理服务状态变化
updateDisplayInfo(ss);
break;
}
}
4. 触发通知
// ServiceStateTracker.java
private void pollStateDone() {
// ... 状态检查
if (hasNetworkAttached) {
mNetworkAttachedRegistrants.notifyRegistrants();
}
if (hasNetworkDetached) {
mNetworkDetachedRegistrants.notifyRegistrants();
}
}
四、高级特性
1. Phone 切换时的迁移 (migrateFrom)
protected void migrate(RegistrantList to, RegistrantList from) {
if (from == null) {
// May be null in some cases, such as testing.
return;
}
from.removeCleared();
for (int i = 0, n = from.size(); i < n; i++) {
Registrant r = (Registrant) from.get(i);
Message msg = r.messageForRegistrant();
// Since CallManager has already registered with both CS and IMS phones,
// the migrate should happen only for those registrants which are not
// registered with CallManager.Hence the below check is needed to add
// only those registrants to the registrant list which are not
// coming from the CallManager.
if (msg != null) {
if (msg.obj == CallManager.getInstance().getRegistrantIdentifier()) {
continue;
} else {
to.add((Registrant) from.get(i));
}
} else {
应用场景:
- GSM ↔ CDMA 切换
- SRVCC (CS 域切换)
- Phone 对象替换
过程:
- 清理已失效的 Registrant
- 遍历源列表
- 排除特定注册者(如 CallManager)
- 迁移到新列表
2. 条件通知 (notifyNow)
public void registerForCarrierAction(int action, Handler h, int what, Object obj,
boolean notifyNow) {
Boolean carrierAction = getCarrierActionEnabled(action);
if (carrierAction == null) {
throw new IllegalArgumentException("invalid carrier action: " + action);
}
RegistrantList list = getRegistrantsFromAction(action);
Registrant r = new Registrant(h, what, obj);
list.add(r);
if (notifyNow) {
r.notifyRegistrant(new AsyncResult(null, carrierAction, null));
}
}
特点:
notifyNow=true: 注册后立即通知当前状态- 避免错过状态
3. 多传输类型支持
public void registerForDataConnectionAttached(@TransportType int transport, Handler h, int what,
Object obj) {
Registrant r = new Registrant(h, what, obj);
if (mAttachedRegistrants.get(transport) == null) {
mAttachedRegistrants.put(transport, new RegistrantList());
}
mAttachedRegistrants.get(transport).add(r);
if (mSS != null) {
NetworkRegistrationInfo netRegState = mSS.getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS, transport);
if (netRegState == null || netRegState.isInService()) {
r.notifyRegistrant();
}
}
}
设计:
private SparseArray<RegistrantList> mAttachedRegistrants = new SparseArray<>();
- 使用
SparseArray<RegistrantList>管理多种传输类型 - WWAN (蜂窝网络)
- WLAN (Wi-Fi)
五、设计优势
1. 内存安全
- 弱引用: 自动避免内存泄漏
- removeCleared(): 自动清理失效注册者
2. 线程安全
- Handler 机制: 通过 Message 在目标线程执行
- synchronized: RegistrantList 的关键方法同步
3. 解耦设计
- 事件发布者无需知道监听者细节
- 监听者可动态添加/移除
- 支持多对多关系
4. 灵活性
- 支持携带自定义数据 (
userObj) - 支持携带结果和异常 (
AsyncResult) - 支持立即通知当前状态
5. 高效
- ArrayList 遍历性能高
- 弱引用自动清理,无需手动管理
- 批量通知高效
六、与标准观察者模式对比
| 特性 | Registrant 机制 | 标准 Observer 模式 |
|---|---|---|
| Handler 集成 | ✓ 内置 Handler 支持 | ✗ 需自行实现 |
| 线程安全 | ✓ Message 机制跨线程 | ✗ 需额外处理 |
| 内存管理 | ✓ WeakReference 自动 | ✗ 需手动清理 |
| 异常传递 | ✓ AsyncResult 封装 | ✗ 通常不支持 |
| 立即通知 | ✓ 注册时可选通知 | ✗ 通常不支持 |
| 数据携带 | ✓ userObj + result | ✓ 通常支持 |
七、实战:自定义事件监听
假设要为 DataConnection 添加状态监听:
// 1. 声明 RegistrantList
private final RegistrantList mDataStateChangedRegistrants = new RegistrantList();
// 2. 提供注册接口
public void registerForDataStateChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant(h, what, obj);
mDataStateChangedRegistrants.add(r);
// 立即通知当前状态
r.notifyResult(getCurrentState());
}
public void unregisterForDataStateChanged(Handler h) {
mDataStateChangedRegistrants.remove(h);
}
// 3. 状态变化时通知
private void notifyDataStateChanged(int newState) {
mDataStateChangedRegistrants.notifyResult(newState);
}
// 4. 监听者使用
class MyController extends Handler {
private static final int EVENT_DATA_STATE_CHANGED = 1;
public void init(DataConnection dc) {
dc.registerForDataStateChanged(this, EVENT_DATA_STATE_CHANGED, null);
}
@Override
public void handleMessage(Message msg) {
if (msg.what == EVENT_DATA_STATE_CHANGED) {
AsyncResult ar = (AsyncResult) msg.obj;
int state = (Integer) ar.result;
// 处理状态变化
}
}
}
八、总结
Android Telephony 的监听注册机制是一个精心设计的事件分发系统:
-
核心组件:
Registrant: 单个监听者封装RegistrantList: 监听者列表管理AsyncResult: 统一结果封装
-
关键特性:
- 弱引用自动内存管理
- Handler 机制保证线程安全
- 支持立即通知当前状态
- 支持异常和结果传递
-
广泛应用:
- Phone 状态监听
- ServiceState 变化
- 数据连接状态
- SIM 卡事件
- 信号强度
- ...
这套机制是整个 Android Telephony 框架的神经系统,连接了从底层 RIL 到上层 Framework 的所有组件!