android的Live架构
MVC、MVP、MVVM的选择
一开始我们在这几种框架上的选择上就没花太多的心思,因为他们都只是为了实现清晰的分层逻辑,差异化的地方无非是讲UI逻辑、交互逻辑、数据绑定逻辑、业务逻辑堆放在那一层的问题。UI逻辑我们定义为UI控件长什么样,放在那里的逻辑。交互逻辑指的是跟用户互动所需要的逻辑。数据绑定逻辑指数据怎么呈现在界面上的逻辑。业务逻辑指的是因为当前业务不同,跟UI无关的一些程序控制逻辑。
只是看起来很美好的MVC

Live1.0架构上看,MVC的架构能够帮助我们进行良好的分层。Activity(或者Fragment)承担了粘合剂的作用,数据请求后的结果也放在里面。控件的交互交互逻辑虽然收敛在对应的Controller里面了,但是Controller之间的交互逻辑需要放在Fragment中,通过Fragment来调用其他Controller的接口。Live业务是一个典型的业务逻辑简单,UI逻辑、交互逻辑多的场景。各种控件之间的交互很频繁,很快的作为粘合剂的Fragment就不可控地膨胀到2000多行。这时候,添加新的功能或者做修改已有的功能,已经显得很吃力,特别各个组件中因为数据、状态而耦合在一起。在交互复杂的情况下,Activity中因为组件交互的接口越开越多,另外接口也有自己特定的业务名称,除了作者别人改动起来很吃力。这时候,我们又意识到交互逻辑必须要细分为组件自身的交互逻辑,以及组件之间的交互逻辑。
另一方面,粘合剂Fragment中装载的数据是几乎每一个Controller都需要的,往往就在初始化的时候将数据注入进Controller中,来完成数据绑定的逻辑。一不小心,数据绑定的逻辑就从Controller中跑到Fragment了。
开发流程
Live1.0架构中,开发一个组件,需要实现View、Controller、Model,另外Controller还需要在粘合剂Fragment中找到对应的回调实现响应的逻辑,跟其他组件互动的部分需要持有其他组建的View(或Controller).
Live2.0架构
Live2.0架构主要想解决三个问题:
- 每个组件能够独立地变化,状态可以被收敛在组件中。
- 用最少量的、统一的接口来解耦组件间的交互,数据的绑定。
- 交互逻辑、数据请求、业务逻辑、UI逻辑可以复用。

模块化
很自然地,我们就想到可以通过模块化、事件通知机制来解决以上的问题。关键的问题在于如何解决Acitivity中存在大量粘合剂代码。传统的MVC框架只解决了分层的问题,并没有指明模块化的方式。另外我们希望模块化不要造成使用上的难度,接口应该统一、简单易学。玩弄过Google官方出的架构Demo,然而他View、Present的接口也是强业务相关的,并不能实现接口的统一化。
我们最后构想的方案是:既然所有的View在onCreateView的时候都要绑定特定的交互逻辑,onDestroy的时候都要进行销毁,那么每个Controller中实现Fragment的生命周期函数回调就是一件很自然的事情。所以最终的解决方案是Fragment只做生命周期函数的分发,所有的Controller实现Fragment的生命周期回调。
调整后,Fragment彻底变成一个生命周期分发的空壳,每一个View对应一个ViewController,View的绑定交互逻辑、交互逻辑都单独地在Controller中变化.
public class TMVerticalVideoFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mRootView = View.inflate(this.getActivity(), R.layout.fragment_vertical, null);
for (LiveFragmentInterface item :
mViewControllerInterfaceMap.values()) {
item.onCreateView(inflater, container, savedInstanceState);
}
return mRootView;
}
@Override
public void onPause() {
for (LiveFragmentInterface item :
mViewControllerInterfaceMap.values()) {
item.onPause();
}
super.onPause();
}
//省略onViewCreated()、onStop()、onResume()等一大波生命周期函数...
@Override
public void onDestroy() {
super.onDestroy();
for (LiveFragmentInterface item :
mViewControllerInterfaceMap.values()) {
item.onDestroy();
}
}
}
事件分发
之前提到,Live业务的各个组件间的交互逻辑频繁(注意:这里说的不是组件自身的交互逻辑,而是组件与组件间因自身状态变化,而需要控制其他组件同时进行变化的组件间交互。我数了一下一共有26种组件间交互)。显然,这些交互逻辑并不复杂,但是常变。使用事件分发就是最好的选择,接口就不允许常常变化。因此我们实现了简单的事件总线来解耦组件间的交互。
数据绑定
Live业务的数据只依赖少量的Mtop接口,但是这些数据却需要共享给各个组件。我们希望每个组件不要关注数据请求的细节,在数据来的时候,只关注自己需要的数据。另外,Live业务有多个数据源(N个Mtop、配置中心数据、PowerMessage).然而并不是所有的组件都需要关注这么些数据。
解决方案:我们认为数据的请求和处理过程同用户的交互一样,是一种特殊的交互逻辑,数据请求的成功与失败回调也是一种事件通知。数据的绑定固化成特定的接口,对数据感兴趣的Controller只需要实现对应的数据接口,就可以接收到对应的数据。所有Controller中数据绑定的逻辑也固化在特定的数据回调接口中。
/**
* MinSk数据读取Controller
* Created by kaihuan on 16/8/18.
*/
public class MinSkConfigurationController implements LiveFragmentInterface {
public static final String TAG = "live.MinSkConfigurationController";
protected IGetController mFragment;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
JSONObject refreshConfigJson = TMConfigCenterManager.getInstance().getConfigDataObject(getConfigName());
if (refreshConfigJson ==null ){
return;
}
//分发数据
Map<String, LiveFragmentInterface> viewControllerInterfaceMap = mFragment.getViewControllerInterfaceMap();
if (viewControllerInterfaceMap != null) {
for (LiveFragmentInterface item : viewControllerInterfaceMap.values()) {
if (item != null && item instanceof IMinskDataListener) {
((IMinskDataListener) item).onMinskData(getConfigName(),refreshConfigJson);
}
}
}
}
@NonNull
protected String getConfigName() {
return LiveVerticalConstants.MINSK_CONFIG_KEY;
}
// 省略一大波生命周期回到函数..
@Override
public void onFragemntCreated(Fragment fragment) {
this.mFragment = (IGetController) fragment;
}
}
开发流程
Live2.0架构中,开发一个特定的组件就只需要实现自己的View、Controller、Model,在自己的Fragment生命周期回调、数据回调中实现自己的逻辑、改变自己的状态。对组件中需要联动的部分,只需要发送事件通知别人改变。
从切身的体会来说,Live2.0架构简化了开发成本,在View产生的方法,在特定的回到生命周期回调函数中只专心地做自己业务相关的部分,而不需要考虑别人的状态变化。在开发过程中,甚至都见不到别人一丝丝的代码.
双十一我们需要实现三个不同的Live间,由于逻辑的切割足够细,代码方面近乎达到100%的复用。对开发、测试同学来说,工作量至少减少2~3倍。
android的Live架构的更多相关文章
- [转]Android App整体架构设计的思考
1. 架构设计的目的 对程序进行架构设计的原因,归根到底是为了提高生产力.通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点, ...
- Android入门(二):Android的系统架构
android的系统架构和其操作系统一样,采用了分层的架构.从架构图看,android分为四个层,从高层到低层分别是应用程序层.应用程序框架层.系统运行库层和linux核心层. 从技术方面看,An ...
- Android系统的架构
android的系统架构和其操作系统一样,采用了分层的架构.从架构图看,android分为四个层,从高层到低层分别是应用程序层.应用程序框架层.系统运行库层和linux核心层. 1.应用程序 Andr ...
- fir.im Weekly - iOS/Android 应用程序架构解析
假如问你一个iOS or Android app的架构,你会从哪些方面来说呢? 本期 fir.im Weekly 收集了关于 iOS/Android 开发资源,也加入了一些关于 Web 前端方面的分 ...
- Android 控件架构及View、ViewGroup的测量
附录:示例代码地址 控件在Android开发的过程中是必不可少的,无论是我们在使用系统控件还是自定义的控件.下面我们将讲解一下Android的控件架构,以及如何实现自定义控件. 1.Android控件 ...
- Android 的系统架构
Android 的系统架构 Android其本质就是在标准的Linux系统上增加了Java虚拟机Dalvik,并在Dalvik虚拟机上搭建了一个JAVA的application framework,所 ...
- Android App的架构设计:从VM、MVC、MVP到MVVM
随着Android应用开发规模的扩大,客户端业务逻辑也越来越复杂,已然不是简单的数据展示了.如同后端开发遇到瓶颈时采用的组件拆分思想,客户端也需要进行架构设计,拆分视图和数据,解除模块之间的耦合,提高 ...
- Android系统四层架构分享
Android系统四层架构 个人网站:http://www.51pansou.com Android视频下载:Android视频 Android源码下载:Android源码 如果把Android系统看 ...
- Android的系统架构
转自Android的系统架构 从上图中可以看出,Android系统架构为四层结构,从上层到下层分别是应用程序层.应用程序框架层.系统运行库层以及Linux内核层,分别介绍如下: 1)应用程序层 ...
- 实时Android语音对讲系统架构
本文属于Android局域网内的语音对讲项目系列,<通过UDP广播实现Android局域网Peer Discovering>实现了局域网内的广播及多播通信,本文将重点说明系统架构,音频信号 ...
随机推荐
- Centos7 动态创建文件系统
linux 想要动态扩展文件系统,需要将磁盘做成LVM动态卷 以centos 7为例 挂载两块磁盘 vdb vdc 安装 ssm 管理磁盘工具 yum -y install syste ...
- 获取sap登陆用户名的中文描述
一.业务场景: 当通过MKPF-USNAM查找ADRP-NAME_LAST时,中间缺少一个表,即USR21.否则,MKPF-USNAM不能和ADRP-PERSNUMBER直接对等. 二.解决方法: D ...
- 高通HAL层之Sensor HAL
高通的HAL层其实分为两种,一种是直接从kernel这边报数据上来的,由sensor HAL层来监听,另一种是走ADSP的模式,HAL层是通过qmi的形式进行监听的: 走ADSP架构的可以看下面的博客 ...
- Linux设置DNS地址及清理DNS缓存方法
1.设置DNS地址 编辑vim /etc/resolv.conf 文件. 增加DNS地址:nameserver ip. 2.清理DNS缓存 清理dns缓存: 通过重启nscd服务来达到清理dns缓存的 ...
- win7下MySQL的安装配置及卸载 笔记分享
一.官网下载地址:https://dev.mysql.com/downloads/mysql/ 1.选择对应版本,下载免安装版: 2.不要注册账号,点击"No thanks,just sta ...
- ECMAScript 6 笔记(二)
ES6中的基本扩展 一.字符串的扩展 1. 字符的Unicode表示法 用两个双字节的形式表达字符时,如果直接在\u后面跟上超过0xFFFF的数值(比如\u20BB7),JavaScript会理解成\ ...
- qt的编译
cp qt-everywhere-opensource-src-5.5.0.tar.gz /opt/qt/2.1 解压qt源码 sudo tar xzf qt-everywhere-opensourc ...
- 织梦使用if判断某个字段是否为空
织梦如何使用if判断某个字段是否为空呢?我们以文章页调用文章摘要为例: 使用if语句判断摘要是否为空,如果有摘要就显示摘要模块,如果没有就不显示 {dede:field.description run ...
- [记]Debian alias 设置, 不设置貌似有点不方便习惯
备忘录,记录下. 不知道 当前有那些 alias 的话 直接输入 alias ,回车就可以看到 alias 列表. 终端输入: vim ~/bash_aliases 然后输入: # some more ...
- Spring context:property-placeholder 一些坑
今天在配置多配置文件的时候偶然发现如果我使用 <context:property-placeholder location="classpath:filePath.properti ...