首先,感谢Google 的开源系统,让我有了一份Android系统工程师的工作;第二,感谢开源系统,让我们以更加开放、自由的精神工作;第三,感谢工程师对知识和经验的共享,让更多的人吸收经验,创造高质的代码,开发更优秀的产品。
MVC 全名 Mode View Controller(模型-视图-控制器),是一种经典的软件设计思路,MVC将业务逻辑、数据控制与界面显示分离,真正实现了代码的高内聚低耦合,是一种上乘的软件设计框架。
用来处理应用程序的数据逻辑部分。通常模型对象负责处理在数据库中存取数据,负责数据的增删改查。要处理的数据接收自控制器。
用来处理数据显示部分,通常视图是依据模型数据创建的,目的是将数据高效的展示给用户。要显示的数据接收自模型。
用来处理用户交互的部分,通常控制器负责从视图中读取数据,控制用户输入。接收到用户的输入后向模型发送数据。
MVC框架最显著的优点是低耦合,比如在Android的SystemUI中,界面的问题只需要去修改View,而不用去更改业务的实现,属于业务逻辑的问题,只需要去修改Model中的逻辑,不应喜爱那个其他,如果业务结果与View更新出现不匹配或者滞后的现象,则去优化Controller中的代码即可;还有一个优点是代码重用性高,同一套代码修改一下View就能在其他的模块实现同样的功能;第三个优点是,生命周期成本低,MVC框架开发出来的代码,不管是添加新功能还是代码维护的技术含量很低。
在SystemUI中BUG比较多的是下拉状态栏中按钮的问题,在修改与按钮相关的bug时逐渐对QuickSettings的设计框架有了一个比较深刻的经验,下面就将我在这方面的经验来分享出来。
选取一个简单的Wifi按钮来做分析,首先来看一下Wifi状态改变时,系统对QST(QuickSetting Title)的刷新。
从这一张流程图中我们可以看到wifi状态参数的接收是在NetworkController.java中,从命名就能看出来它就是控制器,Wifi状态的改变通过接口NetworkSignalChangedCallback的onWifiSingalChanged方法将Wifi状态分发给Model进行处理;针对于QST的业务逻辑是在QuickSettingsModel(QSM)中处理的,QSM实现了NetworkSignalChangedCallback接口,并重写了onWifiSingalChanged,当然在这里面进行了对Wifi状态的更新处理;当处理完之后,按照MVC框架的模式,需要将新的WIFI参数传递给View以好展示给用户,QMS将参数传递给View的方式也是使用回调函数,通过回调接口NetworkActivityCallback的refreshView方法,通知View去刷新界面;而这个接口是在QuickSettings中实例化QST的同时为该QST绑定的。如果上图看的不是很清楚,可以再看下这张据图的时序图:
下拉状态栏中的Buttons分两类,一类是只有简单状态的Button,不用跟随系统参数变化而实时更新显示状态的,Google中称之为UserTitle,比如“设置”、“机主”、“飞行模式”等按钮;另一类是需要实时刷新Button显示的,Google称之为SystemTitle,比如“WLAN”“RISS”等。
Button的组成:
FrameLayout.java
->QuickSettingsTileView.java
->QuickSettingsBasicTile.java
对于UserTitle,呈现的是QuickSettingsBasicTile对象,布局文件如果不指定LayoutId,那么是直接从quick_settings_tile_basic.xml中加载。比如“亮度”的设计如下:
// Brightness
final QuickSettingsBasicTile brightnessTile
= new QuickSettingsBasicTile(mContext);
对于SystemTitle,呈现的是QuickSettingsTileView对象,为了满足界面的刷新,其布局文件为自定义的layout,一般ViewGrop为quick_settings_tile.xml,然后再去设置childView。比如WLAN的设计如下:
final QuickSettingsTileView wifiTile = (QuickSettingsTileView)
inflater.inflate(R.layout.quick_settings_tile, parent, false);
wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
这些Buttons的实例化是在QuickSettings中进行的。
在SystemUI\src\com\android\systemui\statusbar\phoneSettings.java中对View的初始化是从它的setup函数开始,当systemReady之后,SystemUIManagerService会去实例化QS,而Wifi按钮的初始化如下:
BroadCastReceiver.java
-->NetworkController.java,
BatteryController.java,
BluetoothController.java,
LocationController.java.
这些控制器都在SystemUI\src\com\android\systemui\statusbar\policy\下。那么其实除了对下拉状态栏中的QST的显示进行控制外,也控制顶部StatusBar的刷新,将这些Controllers视为MVC里面的控制器完全合理吧。
如图,可看到QuickSettingsModel实现了各种各样的接口,而这些接口又是哪里的呢?
我们从QuickSettingsModel类的依赖关系来看:
QMS实现的接口都是在上面所说的控制器中去定义的。
按照上面的流程,当控制器监听到系统参数的变化后就会回调这些接口中的函数来通知Model业务模块进行数据的处理。
我们已经知道QuickSettings中已经为各个View添加了在QSM中的业务逻辑模块,那么,更新View的事情自然是由QSM负责。看到这里,我想你因该会对QuickSettings QuickSettingsModel 和policy下的XXXXController.java有了 初步的了解。如果还是不太理解,那么请按照MVC框架模式的思路,再去跟进一下某一个按钮的初始化,Touch监听,以及View刷新的流程,应该会对下拉状态栏中的按钮有更新的认识。
在此文章中,并没有出现很多的代码,仅仅挑选出了WIFI 按钮整理了一条思路,如果想要对具体实现有更深的理解,那就去看代码吧。
当理解到下拉状态栏的MVC模式后,应该能针对不同的现象,很快就判断是在MVC的哪一个模块处的问题。我想对于以后的客户需求,或者BUG修改,应该也不会乱写代码吧?最起码应该知道在哪里修改对系统广播处理,在哪里控制快捷按钮的添加与隐藏,又是在哪里修改UI界面显示逻辑的处理。