Android系统之Phone模块-接电话Unsolicited消息的接收和处理过程
2015-09-29 09:25
459 查看
Android的Phone模块是整个系统的核心模块之一,是手机的重要组成部分,所以理解和分析Phone模块的主要流程和原理机制就成了我们学习和开发Android应用程序的重要工作之一。而要对Phone模块进行学习和分析,我觉得接电话的功能是一个非常好的,而且非常有代表性的功能,因为接电话的流程相对比较清晰,并且可以从接电话的过程窥探到整个Phone模块的基本面貌,其中消息的收发和处理也是这中间非常重要的内容。我个人觉得对通过这一步的分析,必会为学习Phone这个模块开启一个良好的开端。
因为电话系统的发展实际远远早于Android系统的开始时间,而电话系统又涉及到非常多和通信协议相关,所以对于Phone这个模块不仅单单是纯粹的Android应用的问题,而且还有通信协议的问题,需要从两个维度去了解并认识。那就以接电话这个功能作为我们认识Phone模块的开端吧。
基于Android系统的整体架构,是一个分层管理的系统,所以对于这次讨论的问题,我们也从两个层次去分析和观察,也可以说是从两个不同的方向梳理脉络。
当我们在接电话的时候,手机会进入的界面是有个类IncallScreen.java所管理的一个Activity,界面如下:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/e81b57e3cb65ed571a84276f81e86617.png)
图一
那对于这个类是怎样监听下层上发的消息呢?我们都知道接收消息一般都会用到Handler和Message,但是在Phone模块中接收和发送消息的时候,使用Handler和Message的这种机制有用得非常巧妙。举个简单的例子说明,那就是在发送消息的时候,通过一层一层的转发,最终到达IncallScreen.java。那它又是怎么样转发的呢?
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/e3533c003bab626a7221a30b7d3a673f.png)
图二
如图二所示,IncallScreen会讲自己的一个handler对象注册到CallManager进行管理,而CallManager通过一个封装好的List来管理注册的handler,这个封装好的List就是类RegistrantList,这个List也在实现这种机制扮演着关键的角色。
请看关键代码:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/950b9129f4329a274991b9b02824b8c4.png)
在这段代码中,mCM是CallManager的一个对象,负责将PHON_INCOMMING_RING和IncallScreen的handler注册,以便IncallScreen获得CallManager的消息通知。CallManager的方法registrantForIncommingRing()方法中做的是就是将传递的Handler和PHONE_INCOMMING_RING保存在RegistrantList中。其实在CallManager这个类中有很多关于注册的方法,这些方法也是构成这个类的主要内容,而注册的这些消息也是构成整个Phone模块的非常核心的内容,因为整个Phone模块的运作机制就是通过消息的注册和通知来实现的,所以我们只要研究了其中一些比较典型的消息,就可以对整个Phone模块
的运作机制有一个整体的了解。
依据图二所示,接下来,我们再进入到类CallManager.java中,因为CallManager是整个消息链路的中介,所以CallManager会同时注册两方面的内容,一个是前面说到的IncallScreen的Handler和message,另一个是会注册处于CallManager下层的PhoneBase的handler和message。我们再来看看在CallManager中有关注册的关键代码:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/fa9eaf3afd35129f57f064285c3bcdf4.png)
可以看出,方法registerForPhoneStates()其实是在PhoneBase注册handler和EVENT_INCOMMING_RING消息,以便获得PhoneBase的通知。而在handleMessage()中做的事情就是将PhoneBase的消息通知IncallScreen,因为mIncomingRingRegistrant注册了全部IncallScreen能接受到的handler和消息。
继续看PhoneBase,这个类也是Phone模块的重要类,承担了很多功能的实现,在这里就只讨论它作为传递消息的角色是怎样运作的。不过还是应该先看看基于PhoneBase这个类所涉及到的类结构:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/155570afe1bf212726123274a346ae48.png)
图三
从上图可以看出,我们在实际的使用的时候是在使用GSMPhone或者CDMAPhone,这两种不同的Phone什么时候使用,取决于手机使用的网络模式是什么类型,并且会在开机的时候进行初始化。
但在这次讨论的话题中,我们先不去深入讨论使用什么网络类型。还是继续消息传递的内容继续探讨。首先再看看PhoneBase中消息注册和通知的关键代码:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/496261eccb2551c2937e822265d1c06f.png)
从类图和代码中我们看出了,PhoneBase本身就是一个Handler,它负责接收底层RIL所上发的消息,这里的EVENT_CALL_RING消息就是RIL发送的。
通过前面的观察之后,那RIL又是怎样将modem的消息转化,然后又通知PhoneBase的呢?接下来我们继续讨论。
Ril.java中的RILReceiver类实现了Runnable接口,实际运行在一个线程中,这个线程始终监听unsolicited类型的消息,其中RIL_UNSOL_CALL_RING是来电消息,在这个消息下,变量mRingRegistrant.notifyRegistrant(new AsyncResult(….))方法用于处理这个消息,接收来自底层的unsolicited类型的message,并发送这个message,最后会被phoneBase的handleMessage()方法获取,并进行相应的处理。那么,PhoneBase怎么会得到这个消息呢?原因在于PhoneBase本身就是一个Handler,它继承自Handler类。而Registrant类的构造方法中,会传递一个Handler对象的引用。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/67b7d7effbd180c846da8ddbf39bda74.png)
在获得相应的Handler的时候使用Registrant的getHandler()方法得到,并在这个方法中使用refH.get()方法返回一个Handler对象,这里涉及到一些WeakReference类的相关用法。而在初始化mRingRegistrant变量的时候是在BaseCommands类的setOnCalling(Handler h,…)中初始化。而在PhoneBase的构造方法中有调用了setOnCalling(….)方法,而且向其传递了一个PhoneBase自身的引用,因为PhoneBase自身是一个Handler,所以mRingRegistrant调用notifyRegistrant()方法后,在方法中得到的Handler就是PhoneBase,所以PhoneBase可以得到这个消息。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/73fd8b41eaa60270de2742256da0f410.png)
图四
在BaseCommands中:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/5120178c3a28cd36fdd0ecfda2313691.png)
在PhoneBase中:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/f8bc9005762590efe6fdc5c97e76042f.png)
在Registrant中:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/09265c126f465a28e150bf53230e47e8.png)
Registrant得到的Handler,就是PhonBase的对象引用,而PhoneBase本身就是一个Handler,所以Registrant中发送的消息,在PhoneBase中可以handle message,他们各自都指向同一个Handler对象的引用。
而对于这样的注册消息的机制,实际上是对观察者模式设计思想的一种应用,对于观察者模式的概念有如下解释:
观察者模式有很多形式,直观的一种就是:
“注册——通知——撤销注册”的形式。
1、观察者
(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
2、被观察对象
被观察对象发生了某种变化(如图中的SomeChange),从容器中得到所有注册过的观察者,将变化通知观察者。
3、撤销观察
观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
而针对Phone这个模块和这次我们所涉及到的内容,请看下图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/abc97f3e83f50ea2a6db7e8883227ca4.png)
图五
当然,我们不能讲观察者模式的概念死板硬套到Phone的模块中,在Phone中队观察者的应用已经对概念进行了灵活的应用,所以我们不能为了模式而模式,而应该对模式的思想做一些思考。
因为电话系统的发展实际远远早于Android系统的开始时间,而电话系统又涉及到非常多和通信协议相关,所以对于Phone这个模块不仅单单是纯粹的Android应用的问题,而且还有通信协议的问题,需要从两个维度去了解并认识。那就以接电话这个功能作为我们认识Phone模块的开端吧。
基于Android系统的整体架构,是一个分层管理的系统,所以对于这次讨论的问题,我们也从两个层次去分析和观察,也可以说是从两个不同的方向梳理脉络。
一、从APP的角度观察
当我们在接电话的时候,手机会进入的界面是有个类IncallScreen.java所管理的一个Activity,界面如下:![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/e81b57e3cb65ed571a84276f81e86617.png)
图一
那对于这个类是怎样监听下层上发的消息呢?我们都知道接收消息一般都会用到Handler和Message,但是在Phone模块中接收和发送消息的时候,使用Handler和Message的这种机制有用得非常巧妙。举个简单的例子说明,那就是在发送消息的时候,通过一层一层的转发,最终到达IncallScreen.java。那它又是怎么样转发的呢?
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/e3533c003bab626a7221a30b7d3a673f.png)
图二
如图二所示,IncallScreen会讲自己的一个handler对象注册到CallManager进行管理,而CallManager通过一个封装好的List来管理注册的handler,这个封装好的List就是类RegistrantList,这个List也在实现这种机制扮演着关键的角色。
请看关键代码:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/950b9129f4329a274991b9b02824b8c4.png)
在这段代码中,mCM是CallManager的一个对象,负责将PHON_INCOMMING_RING和IncallScreen的handler注册,以便IncallScreen获得CallManager的消息通知。CallManager的方法registrantForIncommingRing()方法中做的是就是将传递的Handler和PHONE_INCOMMING_RING保存在RegistrantList中。其实在CallManager这个类中有很多关于注册的方法,这些方法也是构成这个类的主要内容,而注册的这些消息也是构成整个Phone模块的非常核心的内容,因为整个Phone模块的运作机制就是通过消息的注册和通知来实现的,所以我们只要研究了其中一些比较典型的消息,就可以对整个Phone模块
的运作机制有一个整体的了解。
依据图二所示,接下来,我们再进入到类CallManager.java中,因为CallManager是整个消息链路的中介,所以CallManager会同时注册两方面的内容,一个是前面说到的IncallScreen的Handler和message,另一个是会注册处于CallManager下层的PhoneBase的handler和message。我们再来看看在CallManager中有关注册的关键代码:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/fa9eaf3afd35129f57f064285c3bcdf4.png)
可以看出,方法registerForPhoneStates()其实是在PhoneBase注册handler和EVENT_INCOMMING_RING消息,以便获得PhoneBase的通知。而在handleMessage()中做的事情就是将PhoneBase的消息通知IncallScreen,因为mIncomingRingRegistrant注册了全部IncallScreen能接受到的handler和消息。
继续看PhoneBase,这个类也是Phone模块的重要类,承担了很多功能的实现,在这里就只讨论它作为传递消息的角色是怎样运作的。不过还是应该先看看基于PhoneBase这个类所涉及到的类结构:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/155570afe1bf212726123274a346ae48.png)
图三
从上图可以看出,我们在实际的使用的时候是在使用GSMPhone或者CDMAPhone,这两种不同的Phone什么时候使用,取决于手机使用的网络模式是什么类型,并且会在开机的时候进行初始化。
但在这次讨论的话题中,我们先不去深入讨论使用什么网络类型。还是继续消息传递的内容继续探讨。首先再看看PhoneBase中消息注册和通知的关键代码:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/496261eccb2551c2937e822265d1c06f.png)
从类图和代码中我们看出了,PhoneBase本身就是一个Handler,它负责接收底层RIL所上发的消息,这里的EVENT_CALL_RING消息就是RIL发送的。
二、从RIL的角度观察
通过前面的观察之后,那RIL又是怎样将modem的消息转化,然后又通知PhoneBase的呢?接下来我们继续讨论。Ril.java中的RILReceiver类实现了Runnable接口,实际运行在一个线程中,这个线程始终监听unsolicited类型的消息,其中RIL_UNSOL_CALL_RING是来电消息,在这个消息下,变量mRingRegistrant.notifyRegistrant(new AsyncResult(….))方法用于处理这个消息,接收来自底层的unsolicited类型的message,并发送这个message,最后会被phoneBase的handleMessage()方法获取,并进行相应的处理。那么,PhoneBase怎么会得到这个消息呢?原因在于PhoneBase本身就是一个Handler,它继承自Handler类。而Registrant类的构造方法中,会传递一个Handler对象的引用。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/67b7d7effbd180c846da8ddbf39bda74.png)
在获得相应的Handler的时候使用Registrant的getHandler()方法得到,并在这个方法中使用refH.get()方法返回一个Handler对象,这里涉及到一些WeakReference类的相关用法。而在初始化mRingRegistrant变量的时候是在BaseCommands类的setOnCalling(Handler h,…)中初始化。而在PhoneBase的构造方法中有调用了setOnCalling(….)方法,而且向其传递了一个PhoneBase自身的引用,因为PhoneBase自身是一个Handler,所以mRingRegistrant调用notifyRegistrant()方法后,在方法中得到的Handler就是PhoneBase,所以PhoneBase可以得到这个消息。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/73fd8b41eaa60270de2742256da0f410.png)
图四
在BaseCommands中:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/5120178c3a28cd36fdd0ecfda2313691.png)
在PhoneBase中:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/f8bc9005762590efe6fdc5c97e76042f.png)
在Registrant中:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/09265c126f465a28e150bf53230e47e8.png)
结论:
Registrant得到的Handler,就是PhonBase的对象引用,而PhoneBase本身就是一个Handler,所以Registrant中发送的消息,在PhoneBase中可以handle message,他们各自都指向同一个Handler对象的引用。而对于这样的注册消息的机制,实际上是对观察者模式设计思想的一种应用,对于观察者模式的概念有如下解释:
观察者模式有很多形式,直观的一种就是:
“注册——通知——撤销注册”的形式。
1、观察者
(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
2、被观察对象
被观察对象发生了某种变化(如图中的SomeChange),从容器中得到所有注册过的观察者,将变化通知观察者。
3、撤销观察
观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
而针对Phone这个模块和这次我们所涉及到的内容,请看下图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/23/abc97f3e83f50ea2a6db7e8883227ca4.png)
图五
当然,我们不能讲观察者模式的概念死板硬套到Phone的模块中,在Phone中队观察者的应用已经对概念进行了灵活的应用,所以我们不能为了模式而模式,而应该对模式的思想做一些思考。
相关文章推荐
- Android中ViewHolder模式开发的详细解释
- Android 重写系统Crash处理类,保存Crash信息到SD卡 和 完美退出程序的方法
- Android技术交流群
- 2015最新的 导航条《actionbar》给大家分享。
- 如何用AndroidStudio导入github项目
- 使用android快速开发框架afinal的FinalDb操作android数据库
- Android4.4KitKat支持u盘功能
- Android的快速开发框架 afinal
- Android实战简易教程<二十四>(基于Baas的用户表查询功能实现!)
- 【Android】28日问题记录
- Android实战简易教程<二十三>(基于Baas的用户注册验证用户名是否重复功能!)
- Android实战简易教程<二十二>(基于Baas的用户注册功能)
- 我的Android进阶之旅------>Android利用温度传感器实现带动画效果的电子温度计
- Android强制下线功能
- Android高级界面组件的学习(三)
- Android编程实现在自定义对话框中获取EditText中数据的方法
- android 高级知识点
- android View
- android bringToFront()
- android getContext(),Context