CSDN博客:http://blog.csdn.net/niu_gao
我认为android系统中有一个特恶心人的大败笔。就是这个大败笔造成了android系统的卡卡卡不停。
这个大败笔就是对activity的设计。
Android对activity的设计原则是:必须是运行时独立的。
你不能直接创建activity并启动它,必须由系统帮你这样干。你要启动activity,必须用一个Intent请求系统帮忙。所以你要在manifest文件中声明app中的每个activity。如果你有多个activity声明为可启动的并且指定了intent-filter,那么每个activity都有可能成为你app的入口。
既然每个activity都可能成为入口,那每个activity必须是功能独立,自我圆满的。也就是说淡化了进程的概念,一个activity如果destroy了,即使它所在的app进程没有退出且又启动了新的activity,也应该视为这个activity的app退出了。
CSDN博客:http://blog.csdn.net/niu_gao
然而理想太丰满,现实不鸟你。有几个人能有如此共产主义思想与精力把自己的每个activity都搞成像系统的打电话发短信这样的app?大部分activity都是内部使用的,每个都被搞得很独立太费劲了,尤其是app内部的activity之间共享数据时更麻烦,按其原则应把数据放到intent的附加数据中,以startActivityForResult()启动下一个activity,并且在onActivityResult()中接收下一个activity返回的数据,然而如果搞成全局静态数据的话多省事?
这种设计是不是太过分了?你可以杀死与前台app无关的activity或进程,但你怎么能杀死前台app中的activity呢?与其让系统谋杀它还不如让程序员自己去杀它。再说了如果系统内存连一个app的正常运行都维持不住了,那是不是这个app设计得太差了?
还有一个更混乱之极的情况:最新的android系统中提倡导航栏(难道是要跟苹果学,省掉一个键?),于是在导航栏中就有了返回按钮。但是当从Activity A中启动B,然后在B的导航栏上点返回按钮返回A时(在manifest文件中将A指定为B的爸爸),实际上A已经不是原来的A了,而是重新创建了一个,这事是不是太扯蛋了?这种情况下A中的onActivityResult()是永远不会被执行!所以要注意,点导航栏上的返回按钮与点设备的返回键,其效果是不同的,不同的,不同的。。。扯蛋的事情说三遍!
还有,android的开发文档中明确说如果activity中开了后台线程,应该在onDestroy中关闭它。好吧,一般一个app都由多个页面导航完成操作流程,也就是说开多线程的activity在隐藏和显示之间切换时要不停地开关开关开关多线程?
那有没有办法解决这个问题呢?有!可以利用另一个功能独立,自我圆满的组件:service。利用service做后台事务,activity在显隐之间就不会影响到后台任务了,但又要做activity与service之间的通讯,好麻烦。
但有解决办法总比没有强!
还没完,由于这种设计原则带来了更混乱的activity生命周期管理问题!看一下这个图,activity的生命周期多么恐怖!
还有这个图:
(关于Activity的生命周期,详见: http://blog.csdn.net/niu_gao/article/details/7101178)
CSDN博客:http://blog.csdn.net/niu_gao
复杂就算了,更操蛋的是不一致性!本来我们以为onStop()一定对应onStart(),谁知道半路杀出个onRestart()。onStart()之后还不算运行状态,还要再来的onResume() 才算!onCreate()其实并不是对应onDestroy(),而是对应onStop(),我X,可以骂人吗?
但最最扯蛋的是,如果你要保存activity上控件的状态,你需要在onPause()中做!有看官说了,不是onPause(),而是onSaveInstanceState()。是的,实际上是onSaveInstanceState()中,但是onSaveInstanceState()的调用时机是紧跟onPause()的,所以从时机来说与在onPause()中也没多少区别。这就是为什么android界面卡卡卡了!骨子里带的,无法解决!只要引起onPause()调用,必然会伴随硬盘(存储器)操作!也就是再小的activity切换,都会引起硬盘操作!但其实在运行一个app的过程中,这种操作百分之99是不需要的,因为activity跟本没有destroy!所有的控件都在内存中保持着它们的状态呢!为什么IOS界面顺?因为IOS里没有这样操蛋的设计。IOS里的ViewController与activity很相似,但却没有要求必须保持运行时独立性。
android现在有抄IOS的地方,比ListView的替代品:RecycleVeiw,其item的重与机制与IOS的UITableView的cell很相似了,为什么不把activity的设计也向IOS学一下呢?
还有一个扯蛋的设计:就是屏幕旋转时,activity会被destroy再create。跟据前面所讲,可以知道destroy和create过程中的代价有多大。这个过程中app进程跟本没有退出,为毛我要在屏幕旋转过程关闭线程再开启?为毛我要关掉网络再重连?而IOS呢?只是通过一个回调方法给出通知,完全不会关掉view controller再重建。当然由于重建activity,android就有了比IOS更牛B的能力:横屏和竖屏可以有完全不同的layout。其实IOS也可以啊,只要你实现响应屏幕旋转的回调方法,在其中自己用代码调整layout就行了。
我认为android已经认识都是这个错误,所以推出了Fragment这个东西。fragment虽然也有生命周期,但是它不会被系统主动杀死,只要它所在的activity不死,它就一直存在,而且其实你也可以让它离开activity依然活着,而且你也可以决定fragment的生死,如果你想省内存,你可以主动干掉fragment。
有了fragment,你的app可以只有一个activity,建多个fragment,页面切换就是fragment间切换。这样除了屏幕旋转时,大部分情况下不存在销毁和重建问题。不信吗?你可以看到管理fragment的API中,有将fragment加入后退栈的方法,后退栈与导航栏上的后退按钮不正好可以配合写出高效的向导类型的界面吗?所以大家以后要多用fragment少用activity,android推出fragment,就是想让你这样做,只不过不好意思把自己原来的设计全局否定,打自己的脸吧了。(要详细了解fragment,请见:http://blog.csdn.net/niu_gao/article/details/7163263)
以上都是个人偏见,人外有人天外有天,希望有高手来打我的脸。
CSDN博客:http://blog.csdn.net/niu_gao
最后再说一下关于android程序的优化:
- 首先就是按上面所说:多用fragment,少用activity。其实这一条就够了。其它的优化都是针对自己应用的逻辑进行特殊的优化,具体问题具体分析。
- 其次是用最新的API,新开发包总会带来一些优化,或提供新的更高效的组件,比如用RecycleView代替ListView和GridView 。
- 再次是能用C和C++就多用C和C++吧。其实这一条我并不推荐,因为从代码维护角度讲,还是能用java就用java。但如果你非要优化到极限,那就多用C和C++(喜欢NDK和c++并且基础很差的同学可以加入这个群:*535807023)*。
- 最后,如果你不怕麻烦,就自己处理屏幕旋转,大体如下:
为你的manifest文件中的activity元素增加属性:
android:configChanges=“orientation|keyboardHidden”
然后在activity中响应回调方法:
public void onConfigurationChanged (Configuration newConfig)
CSDN博客:http://blog.csdn.net/niu_gao
希望在新的版本中,andorid重拾进程的概念,让大家能自由决定是否将activity搞成运行时独立,进一步向IOS学习,将activity的pause改成“进入后台”,将resume改成“成为前台”,除了生命周期中最主要的create和destroy外,其余的该改名改名,该去掉的去掉。如此则它好我们也好,反正是极好的。