从零搭建Android框架Android-Tractor(一)
程序是什么
做开发工作这么多年,一直忙于或者说陷入到日常琐事当中,一直没跳出来思考,正所谓:“不识庐山真面目,只缘身在此山中”。所以,在工作之余,还是要花点时间,做一些整理,这样一些事情就更清楚了。
在做整理的时候,从手段上来说,如果光用大脑想可能效果不好,还应该动动手,所以就决定一边想、一边写,写一个简单的android前端框架吧。我给它取名叫拖拉机,英文名字直接翻译过来就是tuolaji,哈哈,逗你玩的,是tractor。为什么叫拖拉机呢?我们知道,很多人把软件比作建筑,我也经常这样,但不是很贴切,因为建筑建好了,就待在那,固定不动,没有行为。而车子是可以跑的,所以把软件比作车子更合适的。但是我这个车子就是简单粗糙、能跑就行了,所以叫它拖拉机,最老土的车子,不像什么跑车、赛车速度那么快、拉风,也不像卡车能载多少货物,但是它能跑,这是车子的核心需求,其他的慢慢来嘛,“面包会有的,什么都会有的”!
我把这个项目建在google code上,地址在这里,就作为一个开源项目吧,如果哪位朋友有兴趣,可以加进来。不过,现在还没有开始写代码,当然是先想后做,等想好了就开始动工,所以,还是博客先出来,代码滞后,并且时间上也没保证,毕竟大家都有工作,我会尽量加快进度啦。
好了,我们回到正题,在设计这个框架之前,我觉得有必要搞清楚,程序到底是什么以及它的主要任务有哪些。
程序是工具
看到工具这个词,大家肯定想起那么一句话,人之所以和动物分开,是因为会制作和使用工具。而程序是干嘛用的,给人提供方便的,离不开它工具的本质,它只不过是我们人类使用的千千万万种工具之中的一种罢了,没什么大不了。
既然程序是工具,那么,工具又是什么呢?要回答这个问题,我们主要从工具的任务这个角度入手。首先,来回顾一下人们是怎么使用工具呢?有一句名言:“给我一个支点,我就能撬起地球!”这是说杠杆的,杠杆也是一个工具。我在杠杆这头撬一下,那头地球就起来啦。虽说,这话口气也忒大了,但是揭示了我们使用工具时的一般情形:
1. 输入,我们操控工具
2. 工具内部转化
3. 工具作用于外部世界
4. 效果,世界起了变化
就拿杠杆这个例子:输入就是给杠杆这头一个向下的力(1),杠杆内部转化,使得另一端的力很大(2),这个力作用在地球上(3),那么地球就被撬起来了(4)。
1、3、4应该好理解,至于2,是区别不同工具的关键。谈到转化就涉及到转化谁,转化成什么样子的问题。还是杠杆的例子,转化对象就是这头给的力,转化的结果就是在另一端被放大了。再比如说,放大镜取火,转化对象就是从镜面穿透过的光,这些光被转化成聚焦到一点,从而温度升高,所照之物被点燃。
站在工具的角度,对应上面三点,其主要任务是:
1. 识别操作。
2. 内部转化。
3. 作用于外部世界。
为什么没有第4点呢?至于使用后的效果,虽然这是人们使用工具的目的,但是工具本身并不知晓,所以在这忽略。
对于1,有些工具可能并不需要,是否需要识别操作取决于:
(1) 如果工具需要多个不同的操作的话,并且这些操作对应不同的行为,就需要识别。比如说,车子里的方向盘用来转向;踩油门,用来提高速度。如果不识别,就会对应错乱,假如转方向盘被当成了踩油门,那就大祸临头了。
(2) 如果工具只有一种行为,但是只有特定操作才会引发它,就需要识别。比如说上面提到的杠杆,你不能指望踹杠杆一脚,杠杆就能把地球给撬起来吧。
(3) 如果工具只有一种行为,任意操作都会引起这种行为,就不需要识别。好像这样的工具实际上并不存在,即使存在,也不可控,太危险了。
换句话说,除(3)以外的工具都需要识别操作。而(3)是实际上不存在的,所以所有的工具都需要识别操作。操作识别的目的就是为了启动工具的内部转化。
转化有两种:
1. 把一种程度的A转化成另一种程度的A;
2. 把A转化成B。
对于第一种转化,比如杠杆例子中,一端很小的、向下的力转化成另一端放大很多倍、向上的力。第二种,比如说,踩油门,使得油被燃烧,转化成了热能,进而转化成动能,这个比较复杂,整个过程经历了多次第二种转化。
转化的结果决定了谁、怎样作用于外部世界。这个“怎样”是用来描述“谁”作用于外部世界的属性。比如使用杠杆撬动物体,“谁”就是力,“怎样”代表了力的方向、大小。再比如放大镜取火,“谁”就是光,“怎样”代表了光的密度大小。然后,给一个物体,这些转化的结果作用在它身上,物体就会起变化,力用在物体上,物体可能就会变形、或者造成空间变化;光用在物体上,物体的温度就会升高。不同的“谁”导致物体不同的属性产生变化,不同的“怎样”(属性的不同),导致程度的不同。
而对于程序来说,它所面对的世界,并不是真实的世界,由物组成,而是数据(物的符号)的世界。所以程序改变世界,是通过改变数据来完成。而程序的内部转化也是靠数据实现,所以为了区分,有必要把数据分分类,分别为内部和外部数据。外部数据代表了外部世界,内部数据用于程序工具的内部转化。我们可以把整个内部转化过程,以及外部数据在内部转化后怎么变化,用一个更专业的术语来概括,叫业务逻辑。那么最后一步就是把结果应用到外部数据上。不过,作为前端程序,或者说客户端程序,还有重要的一项就是视图显示。对于普通工具的使用场景来说,外界我们人类是可以感知的,而程序的感知,我们只有通过电脑屏幕,所以视图需要实时反馈外部数据的状态。所以,总的来说,客户端程序一共有四个主要任务:
1. 操作识别
2. 业务逻辑
3. 修改外部数据
4. 视图实时显示数据变化
操作识别
现在我们对每个任务做一下简单的分解。对应操作识别来说,分解下来主要分为三步:
1. 监听输入
2. 分析数据
3. 发出明确的操作
用户操作程序,主要通过键盘和鼠标来输入。现在,触控屏的兴起,就又多了一项:触控输入。首先需要监听这些输入,当这些输入被激发的时候,我们能知道,然后通过分析数据来知道具体信息,比如按键,需要知道按的是什么键,是普通字符键还是功能键比如: Enter、Ctr等。根据这些具体信息,就知道该干什么,对于文字处理程序来说,按字符键A,就是要输入字符a,按Delete,就是要删除后一个字符,按Ctr + C就是要复制选择的字符。这里的输入、删除、复制字符就是明确的操作。它是和程序密切相关的,别的程序,按键A可能就不是输入字符了,可能什么都不干,可能是调整音量。从普通意义上的输入,到程序而言特定的操作,这个之间的转换,是需要定义的。一般情况下,这个定义,是我们直接设死的。而有的程序,比如eclipse里面的功能键设置,就可以让人自定义功能键到操作的转换,是一个比较好的特性。
业务逻辑
业务逻辑,我们前面已经花了大量篇幅来讲这个,它是程序最重要的部分。每个程序,它们的业务逻辑都不一样。所以只能从目的上来说一下,它是为外部数据服务,最终目的是为确定需要修改谁、怎么修改。并且业务逻辑会产生大量内部数据,这些数据在操作的时候是有用的,但是可能操作结束后,就会消亡;也有可能一直存在,直到程序关闭。
外部数据
外部数据就是是程序改变的对象,也可以说是程序这个工具所需要改造的世界,它分为三个部分:
1. 数据的构造
2. 数据的修改
3. 数据的保存
程序需要改造的这个世界,并不是先天就有的,需要我们来构造。并且,由于程序运行在电脑之上,电脑需要关闭,程序也需要关闭,所以这个由数据组成的世界需要把最近的状态保存下次,再次运行程序的时候,需要加载这些数据,来恢复整个世界。在恢复之后,接受操作对数据的修改,然后再保存下来,等下次程序的关闭、打开,如此往复。
视图显示
视图变化主要来自三个方面:
1. 视图自己对操作的反应
2. 视图对内部数据的显示
3. 视图对外部数据的显示
应该说视图对外部数据的显示是最主要的,对内部数据的显示,一般用于对转化过程的反馈。而对操作的显示,比如说一个按钮,鼠标移过的时候,可能会高亮,这些都是辅助性的,为了对用户更友好一些。视图对数据的显示过程分为以下几步:
1. 知晓数据产生了变化。
2. 视图得到更新后的数据
3. 视图显示这些数据。
在1里面,“谁”知晓数据变化,进而通知视图更新数据,有不同的策略,这在以后的文章里面会提到,今天就点到为止了。
视图还有一个作用就是接受系统输入,在前面提到过监听输入,其实就是从视图上监听的,系统的输入由视图来接受,并且视图通过发事件的方式来告诉程序其他部分。