Android随想
初步接触Android,自己尝试做了几个DEMO,感觉到很兴奋。刚刚翻开书的时候,看到Android的五个部件,加上一些文字的描述,感觉很抽象,似乎这个程序不好开发,当我开始动手做了第一个demo之后,就深深的被Android的开发模式吸引了,个人理解是按照Android的开发模式开发了之后放到JAVA编译器,然后再经过DX编译器编译最后简单的部署到手机上。我曾是一个Web开发工程师,非常熟悉基于C#的网络开发,也曾经接触过普元的SOA开发,其实他们之间都有一些类似之处。ASP.net也是将aspx先转为C#的代码然后转换到MSIL中去,普元的SOA是自己扩展了Eclipse的插件,然后把一些编程模式放到工具去,通过普元的解释器解释成java代码然后转换成字节码,但是这个解释器做的相当不完善,同时java的中间编译经常出错,而且速度还跟不上来。
手机是一种特殊的设备,因为它资源的有限性,使得它运行的程序都有很大的限制,开发程序的时候必须考虑到它的硬件。以Sun为主的Java阵营提出了J2ME的开发模式,充分的考虑了开放性和兼容性,于是广博的胸怀得到了业界的认可,但是却没有得到业界的大力推动,J2ME仅仅是附属于各大手机操作系统的一个小产品,它的功能仅仅在提供非主流的程序应用,并不是工程师们不想去做,而是他天生就是作为一门锦上添花的工具来设计的,http://rgruet.free.fr/public/BD-J/,因为JAVA本来就是设计在一个沙箱里头的,所以J2ME只能获得有限的能力,不管是CLDC1.0还是CLDC1.1,区别只在CLDC支持浮点数运算,以及支持浮点数运算的相关的方法的支持,尽管MIDP的出现能够使得图形图像的变化变得更加容易,更加适合做游戏,但是还是无法变成主流的MMI的开发语言。
由于本人对MMI的基础才刚刚开始,对MMI的理解还不够深刻,但是觉得Java在手机MMI的出现还是不太现实的,因为毕竟JAVA的执行还必须有一个VM的支持,一般来说这个VM是独立于手机操作系统的,本来手机的操作系统就很受局限,主要有多任务的操作系统和非多任务的操作系统,有的可能是简单的任务调度系统,在这样的机器上就不可能对VM以及java有太多的幻想。
现在出现的主流的智能手机的操作系统像Nokia的Symbian,MS的Windows Phone/Windows Mobile,Plam的PlamOS,Moto使用的ucLinux,BlackBerry的blackberry,IPhone的mac,Android大系的Android系统大部分是基于C/C++来开发的,MMI似乎都没有用java的,这就是由于主流的Java移动开发的天生的定义而导致的。无论是智能机还是非智能机,对于java的描述都是Java扩展,这个扩展就意味着Java不能登大雅之堂。结合我们对java的用户体验来说,java程序的用户体验一般来说都是比较糟糕的,就移动开发而言,每次运行java程序,都需要一个较长的加载时间和退出的时间,相比起其他程序,这在用户体验中就相当的不利,而且遇到异常的是总是哐当一下就弹出一个莫名的窗口死掉了,这样的人机交互是相当糟糕的。
这或许跟Sun推行的Java策略在市场上不太好的缘故,对Java缺乏一个大的愿景,不断的有组织开会提议加一个JSR,然后就费了很长时间制定一个JSR,而且这个JSR往往在敲定的时候又已经落伍了。前段时间看到一幅漫画,心中真是难受,那幅漫画说的是Duke(Java的吉祥物,有个红鼻子的小家伙)站在Sun的墓碑前掉泪。虽然Java作为现在最广泛使用的编程语言,就移动这一块来说,真的很有局限。
操作系统和VM的结合是Java受阻的原因之一,.Net战略的优势也在于在Windows Mobile里头有一个很好的CLR。或许你有一个这样的用户体验,在Windows上运行的程序,Java写的往往要感觉比.net写的运行得慢,就是因为CLR是对操作系统和硬件做了优化的,而JVM必须支持通用的操作系统和通用的硬件,毫无疑问地说,Eclipse是一个非常优秀的使用java来写的IDE。因此MS的Windows Mobile的优势在于,只要.Net Framework有什么新的东西,对应的CF就有新的东西,而且Windows的UI已经让人非常习惯了。
对于Java来说,除了Sun推出一个Solaris的移动版,有可能会使得Java变成手机移动开发的主力军,但是他没有。所以希望Symbian,ucLinux去完成这件事,事实证明,这个使命没有完成。就用户体验来说,对于许多中低端的用户会非常喜欢Nokia,就一个终端用户而言,不期待能用手里微薄的工资买一个iPhone,Nokia的高端机,Nokia的市场战略非常出色,就我自己而言,用过几大牌子的手机,最后还是愿意情归Nokia,就是因为它的MMI做的人性化。从网上的消息得知,Android的机器的售价应该是iPhone的一半,或者还能有所下降,相信它的市场会因为它友好的MMI见长。
Android在MMI开发中引入了Java,这个时候的Android并没有拘泥于J2ME的一些死板的JSR,构建在Linux上的Android使用了一个相当优秀的操作系统,就内核而言Linux无疑是业界承认是相当稳定的。见网上的一篇帖子,说有公司对比了Android内核和标准的2.6.25版本的Linux内核,发现了Google修改了75个文件,增加了88个文件,该公司还对这些文件都做了对应的注释,其中为Glodfish增加了44文件,这个是虚拟机的虚拟CPU,模仿的是ARM926t;为YAFFS2修改了35个文件,因为增加了对NANDFLASH的支持;为蓝牙修改了10个文件;为调度器修改了进程调度和时钟相关策略,5个文件;为Android的新子系统增加了28个文件,有IPC Binder,运行的进程能为其他进程提供服务,这个功能已经在Plam的软件里被使用了;Low Memory Killer是在内存紧张的时候根据策略关闭某些程序的功能,内核有实现,Google重写了;Ashmem,匿名共享内存,多个程序可以使用这个共享内存获取信息;RAM Console and Log Device,Android增加的日志模块;Android Debug Bridge,Android的调试工具;还有Realtime clock,timed GPIO等;Google还重写了电源管理,文档说,这个是最复杂难度最高的一个功能,放弃了APM、DPM;此外还有36个文件被修改了,设计Android的许多小功能。不过因为Android的内核屏蔽了太多的硬件驱动,会对很多Linux的硬件企业造成堡垒,Linux的内核维护者宣布将Android核心代码从Linux内核中删掉,同时很多企业正试图从他们的代码库中去除Android的代码。因此,Android的发展也不是一帆风顺的,但是它漂亮的MMI是各大厂商都不愿意放弃的,因为实在没有多少个厂商能做到这样的一个系统而且还开源,纵然有缺点,我们也要包容这个可爱的绿色机器人。
一个强大的内核支持下的手机操作系统,相当的健壮,至少在底层是相当的强壮。仔细观察Android的架构图,蓝色的部分是用Java来写的,绿色的部分使用C/C++来写的,红色的部分是采用C来写的,黄色的部分是采用Dalvik虚拟机来写的。看Libraries是和Android Runtime在同一层,而且Android Runtime和Linux Kernel是没有交集的,而是直接嵌入到Libraries的。我猜想,Android Runtime的Core Libraries,应该是利用native关键字引用Libraries的C/C++的函数,通过Dalvik虚拟机再编译完后调用Libraries的函数。经过我对源码的阅读,的确发现有许多标有native关键字的方法。不得不相信Dalvik是一个非常优秀的虚拟机,否则是不足以完成这些工作的。
Dalvik虚拟机是Google的Android团队的工程师设计的,和传统的JVM不一样的是,Dalvik虚拟机是基于寄存器的架构,而普通的虚拟机用的是基于栈的架构。在这里穿插一下虚拟机的设计方法,虚拟机既然被称作机器,就是因为其输入时满足某种命令集架构的指令序列,中间转为某种指令集架构的指令序列并加以执行,主要分为基于寄存器的设计和基于栈的设计,现在出现的大部分的虚拟机采用的都是基于栈的设计,虚拟机模拟的是硬件,从硬件来看,现在的CPU采用的都是基于寄存器的设计,其实也就是说采用寄存器的设计是有优势的,但是为什么虚拟机都不采用寄存器的设计呢?首先,使用基于栈的架构的话,指令会变得简单,不需要考虑指令中的源寄存器和目标寄存器,不需要考虑为临时变量分配空间,求值的时候开辟栈空间就好了;此外,使用基于栈的架构用的是零地址指令,这样的话比其他的指令形式更紧凑,节省资源;另外,考虑到移植性,即使是基于寄存器的架构的CPU,寄存器的个数也不一样,32位X86的通用寄存器就只有8个,而32位的ARM处理器就有16个通用寄存器,然而SPARC却有24个通用寄存器。假使一个虚拟机采用基于寄存器的架构,为了高效执行一般会希望把源架构的寄存器映射到实际机器的寄存器上,如果源架构的寄存器比实际机器的寄存器要多的话,寄存器就不能一一映射了,效率上肯定打了折扣,然而使用基于栈的架构的话,在实现虚拟机的时候就比较好分配实际机器的寄存器,作为优化,基于栈的虚拟机可以采用编译的方法实现。
Dalvik虚拟机的许多设计是考虑到与JVM的兼容性的,采用了基于寄存器的架构,指令码采用二地址和三地址混合形式,目标机器架构明确,主要是针对ARM处理器的支持,ARM9有16个32位通用寄存器而Dalvik虚拟机也是用16个虚拟寄存器,因此它也不需要考虑很多可移植性的问题,优先考虑在ARM9上以高效的方法的实现,这个战略和微软的技术战略是非常象的。
看以下代码:
public class Demo { public static void foo() { int a = 1; int b = 2; int c = (a + b) * 5; } } |
经过javac的编译后,可以看到Demo.class的foo()的代码是:
0 iconst_1 1 istore_0 [a] 2 iconst_2 3 istore_1 [b] 4 iload_0 [a] 5 iload_1 [b] 6 iadd 7 iconst_5 8 imul 9 istore_2 [c] 10 return |
接着使用Android SDK的tools目录里头的工具dx工具,这里是SDK的tools不是根目录的tools文件件,这个DX工具可以是Android 1.5/1.6/2.1的,使用DX工具来讲Demo.Class转化为dex格式,转换的时候可以直接以文本的形式dump出dex的内容,使用下面的命令:
dx --dex --verbose --dump-to=Demo.dex.txt --dump-method=Demo.foo --verbose-dump Demo.class |
可以看到foo()的字节码是:
0000: const/4 v0, #int 1 // #1 0001: const/4 v1, #int 2 // #2 0002: add-int/2addr v0, v1 0003: mul-int/lit8 v0, v0, #int 5 // #05 0005: return-void |
另外Dalvik的.dex问价在未压缩的状态下的体积通常比同等内容的.jar问价在deflate压缩后还要小,但是光从字节码来看,java的字节码总是要比dex的小,这主要是.dex使用了共享的常量池,使得相同的字符串数字常量只会出现一次有效的压缩了文件的大小,不过在JSR200也提到了这样的压缩方法。
回到五彩斑斓的Android架构图上,剩下的两层都是纯蓝色的,一层是Application Framework,一层是Applications。我们经常说的使用Eclipse结合ADT开发的是Applications层,它的开发模式和众多的功能是由Application Framework来支持的,我猜想应该这两层就是Android的MMI了吧,这两层都是纯JAVA来开发的,这两层的资料相当的多。应该赞叹一下这个框架,因为这个框架下的人机交互相当的友好,看起来让人赏心悦目,虽然很多公司都在做手机的MMI,能做得如此人性化的真的很少,而且还无私的开源。另外值得一提的是,这个框架的源代码是开源的,但是要通过Git和repo来获得,repo必须在linux环境执行,因为repo是个shell文件,至于Git有Windows版本的,但是在公司我下载了很久都无法连接上,不知道是不是由于公司的网络管制比较严格的缘故。说起网络的问题,Android模拟器的上网我也迟迟没有弄成功,使用了网上说的三种方法都不成功,加上平时使用的经验发现,除了IE,好像其他程序都无法连到外网。使用网上下载的源码包可以在开发程序的时候看到框架的源代码,但是网上的源码只更新到2.0版本,一直传闻Google没有对2.1进行开源。从网上下载的代码也不过只有20来兆大小,但是这20多兆的代码没有办法在Eclipse里头编译,只能在Linux下编译,听说编译的临时文件非常大。由于没有办法拿到源码和参与预编译的文件,我也无法验证这一说法的真伪。因为在Windows里头搭建编译环境也不是没可能的,已经有高人,使用Windows的环境模拟Linux的来编译了Android的模拟器,这个模拟器的最新代码无法获得,只能获得之前的一个旧版本,我拿回来之后,按照高人的方法去编译,果然出现高人说的一些问题,但是高人把编译好的模拟器截图,并说明要最新的代码。
最后说说这个开发模式,因为这是纯java的MMI,这个时候的Java就可以大显身手,没有J2ME的局限,也没有沙箱,这给了Java很大的空间。由于本人之前开发过较长时间的Web程序,发现了很多很熟悉的地方,使用XML来布局可以类比JSP里头的Html布局,使用AndroidManifest.xml来做配置文件,就像J2EE里头的web.xml一样规定着什么可以运行,如何去运行,还有一个自动生成的管理资源的R文件就像ASP.NET里头自动生成的代码,呈现和业务的分开,另外使用了SQLite,就如同在Web开发的数据库开发一样,和Web开发不同的是,Android 的应用开发有独特的Service组件和Intent的消息传递。这样的开发模式的好处在于每个程序都有相当大的独立性,而且程序之间是非常平等的,这个很重要,在J2ME里头,Java程序和其他程序可不是平等的,如果你愿意,你可重写Android的每一个应用程序,包括拨号,短信息,联系人等等,也给了开发人员相当大的自由度。另外,Android的Java开发使用了很多Java5的新特性,也大大的加速了java程序的开发。