在Tele工作时,遇到过很多的Registrant,此前没有系统的研究过,趁此空挡,查看了下源码,算是做个笔记。
个人对于Registrant的理解是:一个对象A向另一个对象B注册消息,当B满足或者受到这个消息的时候,就通知A,A在此时去处理某些事。例如在创建Phone对象是,GsmCdmaPhone 会向Ril去注册一条voice_radio_tech_change的消息,当ril收到modem上报的voice_radio_tech_change时候,就会广播出这条消息给GsmCdmaPhone,然后GsmCdmaPhone做相应的处理。其实这也就是一种消息的传递。
部分代码实现如下:
http://androidxref.com/8.0.0_r4/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java#265
/**
*GsmCdmaPhone#initOnce
* 初始化phone对象是向Ril注册消息
*/
mCi.registerForVoiceRadioTechChanged(this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
在Ril.java里查看该方法的实现
http://androidxref.com/8.0.0_r4/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
/**
* 在Ril.java中未发现该方法的实现,
* 继续在其父类中寻找
*/
public final class RIL extends BaseCommands implements CommandsInterface
http://androidxref.com/8.0.0_r4/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/BaseCommands.java
/**
* 该方法由三个参数,分别为Handler,what,obj;
*
*/
@Override
public void registerForVoiceRadioTechChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
mVoiceRadioTechChangedRegistrants.add(r);
}
继续查看该注册方法的具体实现
http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/os/Registrant.java#28
/**
* 首先为创建了Registrant的对象,查看其构造函数
* 传入的三个参数
*/
public
Registrant(Handler h, int what, Object obj)
{
refH = new WeakReference(h);
this.what = what;
userObj = obj;
}
/**
* 其次查看mVoiceRadioTechChangedRegistrants
*
*/
protected RegistrantList mVoiceRadioTechChangedRegistrants = new RegistrantList();
public synchronized void add(Registrant r) {
removeCleared();
registrants.add(r);
}
至此,GsmCdmaPhone 已经执行完了mCi.registerForVoiceRadioTechChanged(this, EVENT_VOICE_RADIO_TECH_CHANGED, null); 即GsmCdmaPhone向 Ril注册了一条voice_radio_tech_changed的消息。
既然已经注册了消息,那么当满足该消息时,RIL应该告知该注册者。
代码如下:
http://androidxref.com/8.0.0_r4/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioIndication.java#619
/**
* 当voice_radio_tech_change的时候,mVoiceRadioTechChangedRegistrants会去通知所有注册这条消
* 息的对象
*/
public void voiceRadioTechChanged(int indicationType, int rat) {
mRil.processIndication(indicationType);
int response[] = new int[1];
response[0] = rat;
if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, response);
mRil.mVoiceRadioTechChangedRegistrants.notifyRegistrants(
new AsyncResult (null, response, null));
}
查看下notifyRegistrants的具体实现
http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/os/RegistrantList.java#registrants
/**
* 该方法有较多的重载,最终的实现如下
* 该函数遍历所有的注册对象,然后向每个对象发出通知
*/
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);
}
}
http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/os/Registrant.java
/**
* 该方法几个关注点:
* getHandler():在前面Registrant的构造函数里有看到,这个handle为注册时传入的第一个参数
* 如果该handle不为空,则就是一个handle的消息的send
*/
/*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);
}
}
即 mRil.mVoiceRadioTechChangedRegistrants.notifyRegistrants(new AsyncResult (null, response, null))执行完后,会告知之前的注册对象现在voice_radio_tech变化了。
从前面的代码来看,GsmCdmaPhone 在向Ril注册时,有三个参数,前两个参数分别是:this & EVENT_VOICE_RADIO_TECH_CHANGED.从之前代码的分析也可以看出,第一个参数的this会最终传到Registrant,作为Registrant构造函数的一个参数,并在最终会通过handler发送出去。第二个参数的EVENT_VOICE_RADIO_TECH_CHANGED 也是作为一个构造函数的一个参数,最终发送回去。
那么最终对于这个消息的接收和处理也就比较好理解了:
http://androidxref.com/8.0.0_r4/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java#handleMessage
/**
* 最终的实现
*/
case EVENT_VOICE_RADIO_TECH_CHANGED:
case EVENT_REQUEST_VOICE_RADIO_TECH_DONE:
String what = (msg.what == EVENT_VOICE_RADIO_TECH_CHANGED) ?
"EVENT_VOICE_RADIO_TECH_CHANGED" : "EVENT_REQUEST_VOICE_RADIO_TECH_DONE";
ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
if ((ar.result != null) && (((int[]) ar.result).length != 0)) {
int newVoiceTech = ((int[]) ar.result)[0];
logd(what + ": newVoiceTech=" + newVoiceTech);
phoneObjectUpdater(newVoiceTech);
} else {
loge(what + ": has no tech!");
}
} else {
loge(what + ": exception=" + ar.exception);
}
break;
PS:个人理解,对于该功能的实现,就是那里注册,最终那里接收实现。在某个地方看到了notifyRegistrants,那么就寻找该Registrants的定义,然后查看哪里去register,并且register了什么消息。那么同时也就看到了这个注册消息的实现。