以前有段时间写Windows桌面程序悟出的道理。java
是这样的,有时候,咱们须要建立一个符合业务的View,或者称为UI对象,好比,即时通信软件的好友列表里面的每一个item,那么这个item要有头像,名字,简短描述三个数据项。那么,咱们这个View对象,就得有三个对应的方法来设置这三个属性,而后View显示的时候,就显示出咱们最新的数据就行了。网络
最最最开始的时候,我都是耿直的写成这样。spa
// 如下是伪代码的形式,并不严谨 class UserItemView extends View { ImageView mAvatar; TextView mName; TextView mDesc; public void setAvatar(Bitmap avatarImage) { mAvatar.setImage(avatarImage); } public void setName(String name) { mName.setText(name); } public void setDesc(String desc) { mDesc.setText(desc); } }
在最开始的时候,这样是OK的,看起来很是完美,没有任何问题。若是某个用户的数据变了,就更新某个数据就行了。设计
好,如今问题了,这样写的问题在于,当状态/数据之间相互依赖对UI的显示产生影响时,那么就会出问题,代码会混乱。code
咱们如今提个这样的需求,若是描述(desc)是空的,就显示出头像,若是不是空的,就不显示头像。
需求确实很奇怪,可是实际的工做中必定会遇到相似的状况。对象
那么,首先咱们想固然的改动一下代码吧。事件
class UserItemView extends View { ImageView mAvatar; TextView mName; TextView mDesc; String mDescData; public void setAvatar(Bitmap avatarImage) { mAvatar.setImage(avatarImage); } public void setName(String name) { mName.setText(name); } public void setDesc(String desc) { mDescData = desc; if (mDescData == null || mDescData .equals("")) { mAvatar.setVisible(true); } else { mAvatar.setVisible(false); } mDesc.setText(mDescData ); } }
你看,如今设置描述的方法里要去管头像的显示状况,这就很恶心了。若是有更多的数据项和状态,更多的UI控件,他们之间有很是多的依赖关系,若是按这样的写法,你的每一个方法里面的逻辑都会变得很是恶心,复杂。甚至,设置某个UI的状态还须要依赖其余的数据项,你没办法,只能把无关的数据当参数传入,就会变成这样。图片
// !!!爆炸!!!为何头像要关注其余的数据!!! public void setAvatar(Bitmap avatarImage, String desc) { mAvatar.setImage(avatarImage); if (desc== null || desc.equals("")) { mAvatar.setVisible(true); } else { mAvatar.setVisible(false); } }
当时,我那个UI已经变得很是恶心了,在这样的状况下,我终于意识到,对UI对象的更新,不能就地去作,UI对象的更新,应该用一个统一的方法来作,而会改变UI显示状况的那些setXXXX
方法,只作两件事,一是把数据设到这个对象的成员属性上,另外一件事就是调用统一的方法来更新UI。it
其实一个标准的设计一直在眼前,直到那一刻,我才意识到和真正的理解。那就是Android中的View
。Android中的每一个View
的子类,都有超级多的set
方法,好比TextView
,就有setText
,setTextColor
等等。它就是每一个set方法,其实是给这个对象作一个数据上的变化,而后就无论了。等到系统来调用OnDraw
方法的时候,在OnDraw
方法中统一的来更新UI。class
接下来就简单了。咱们的代码改为这样:
class UserItemView extends View { ImageView mAvatar; TextView mName; TextView mDesc; String mNameData; String mDescData; Bitmap mAvatarData; public void updateView() { mAvatar.setImage(mAvatarData); if (mDescData== null || mDescData.equals("")) { mAvatar.setVisible(true); } else { mAvatar.setVisible(false); } mDesc.setText(mDescData); mName.setText(mNameData); } public void setAvatar(Bitmap avatarImage) { mAvatarData = avatarImage; updateView(); } public void setName(String name) { mNameData = name; updateView(); } public void setDesc(String desc) { mDescData = desc; updateView(); } }
注意到,添加了一个updateView
方法,这个方法专门用来将数据更新到UI上,这样写,其余set
方法一概只作把数据存进来的事情,updateView
方法专门根据当前的数据状态更新UI,这样set方法就干净整洁。而逻辑再复杂的显示逻辑,都不用怕,在updateView
里面搞就好了。
我曾经而且一直在维护的一个Activity,它大概有15+个View,20-30个数据和状态,这些数据和状态会谜通常的印象着这些view的显示。当时年轻不懂事,就耿直的在数据变化的后面(下一行),立马就更新UI的状态。有以下这些位置吧:
点击事件
系统回调
网络请求回调
定时器,handler
这么多地方都在更新数据,而且改变UI,维护起来简直要屎。
后来,在我领悟到上面这个技巧后,我重构了一波,里面有个超级大的updateView方法,而后对每一个View进行更新。
这里有另外一个小技巧,就是你有1w个View,和1w个状态,你按状态分类写,仍是按View分类写。这个意思就是:按正常人思惟吧,好比你的页面有两种模式,通常人就会写
if (mode == A) { viewA.xxxxxx viewB.xxxxxx ... } else if (mode == B) { viewA.xxxxxx viewB.xxxxxx ... }
这样写又出问题了,少年,你觉得你的状态只有两种吗?你觉得每一个UI对象,就只依赖一个状态吗?会这么优雅的恰好分布在if和else里面吗?你错了,需求这个东西啊,是很是恶心的,彻底不符合逻辑的。
这样写呢,当你状态不少不少的时候,你很难去安排这个view的更新放哪里,若是有新加的状态又影响到它。为了避免影响到以前的逻辑,你每每就是再后面再加上一行,这样多了也是难以维护的。
那样怎么作呢?最简单,按View来分类写。你有1w个View吧,那就挨个挨个来,先把第一个View处理好了,第一个View受那些影响呢?所有写出来,if-else也好,什么都好,反正最开始这几行代码,先把View1搞定。
而后再一次写View2,View3的逻辑,这样惟一的缺点就是,你的判断得重复写。看上去很累赘,view1和view2,极可能他们的显示逻辑是相同的,你很是想把他们写在一个if-else里,可是我建议你不要这么作,为了最高的变通性,请将他们分开写。
当你往后维护的时候,哪一个View出问题了,你只要找到那一坨就行了,别的都不须要管。
祝各位工做愉快!