搞 Android 开发有一段时间了,相信很多从 Windows 开发过来的 Android 程序员都习惯性地会跟我一样遇到过同一个问题:如何彻底退出程序?这里说下我自己的经验,并不权威,仅供参考。
一开始我也上网到处找退出的资料,网上这方面的文章也是很多,总结下来退出Android程序的方法大概有以下几种:
1、直接调 System.exit(0) 或直接用 android.os.Process.killProcess;
2、调用 ActivityManager.restartPackage 或 killBackgroudProcesses;
3、搞个 Activity 堆栈列表,把所有 Activity 通过继承基类或调用函数的方式记录下来,退出时逐一 finish;
4、故意制造致命错误,然后利用错误强制退出;
5、搞一个 singleTop 的根 Activity,通过它自动清除 Activity 堆栈再退出;
6、调用隐藏的 ActivityManager.forceStopPackage 方法
不过这些方法经过试验基本上都不完美,要不就是退不干净,要不就是只支持 2.2 以下旧版,要不就是要求 ROOT权限。其中 System.exit(0) 和 android.os.Process.killProcess 能结束当前 Activity,有时候能结束当前 Activity 和上一个 Activity,但再多的话基本上就不行了。
相对比较完美的就是自己做 Activity 堆栈列表来释放了,有一段时间我也采用了这一方法,觉得不错,问题好像是解决了,不过解决得相当难受,自己做 Activity 堆栈,意味着每个 Activity 都要继承同一个父类。我一边调试程序一边咒骂谷歌,你乍就不能提供个好用的退出接口?
好景不长,没多久我发现,程序只把 Activity 结束了,但程序并没有退出,后台还有几个线程在跑,退出后过了好久还会提示出错,真是气死人不偿命。我想要求程序退出前等待线程一下吧,结果发现那几个线程并非是我自己创建的,而是用了第三方的一个地图组件在后台下载数据。最后我出了个毛招,把 Thread.UncaughtExceptionHandler 接管,把错误截了不显示。
原来,我们只是把 Activity 界面结束了,但界面结束后,只要有线程在跑,程序其实仍在运行,可谓马照跑舞照跳。Activity 关闭后只是界面消失了,其它该有的东西完全是照常进行;如果线程中有网络请求,则还是照样占用CPU 和带宽。
继续研究,发现一个有趣的现象,程序退出后,再次启动程序,发现用 public static 声明的全局变量居然没变。什么意思呢?举个例子,如果你的 MainActivity 中有一个全局静态变量 public static int c,默认值为 0,程序第一次启动你在 onCreate 里设置它加1,即执行 c+=1 或 c++;然后你关闭程序,马上再次启动程序,这时 c 的值仍为 1,并没有清为 0,执行 c+=1 之后它会变成 2;然后你不停地打开关闭程序,就会发现 c 值在不停地增加。
接着很自然就会再研究 Android 的 Application,因为据说 Application 在程序中是比较唯一的,适合放置全局变量。我在程序中创建并使用了自己的 Application 类,然后同样在里面放全局静态变量进行赋值测试,结果照旧——程序关闭再启动时系统并未清除全局变量。
于是我在 Application 的 onCreate 中写启动日志(它还有个 onTerminate 事件,不过实践并看完帮助后才知道那个是假的),结果发现,onCreate 其实只在第一次启动时调用,第二次启动时并没有重新创建 Application。意思是什么呢?悲哀呀,我们的程序根本就没退出。
原来我们 Activity 关闭后程序并没有结束,我们的结束程序其实只是演给自己看,本质上程序压根就没退出,程序就一直在后台,除非你用具有 ROOT 权限的任务管理器结束,否则它永远不会主动退出。
当然了,我以上试验都是在内存充足的情况下进行。程序虽然不会主动退出,但内存清理时系统还是会被退出的。由于谷歌没提供退出的功能,因此很明显,谷歌就是要我们知道,你不必主动退出程序,我会在需要时帮你退出。
对于习惯退出的 PC 程序员来说,这真是没天理啊,凭啥我退出了你还要占着宝贵的内存?甚至说不定还占着其它资源。我一开始也很不理解,不过后来一想,其实内存占着也无所谓,只要不占 CPU,内存平时空着也是浪费的,反正也不耗电,当下一次加载时还能提速,而内存不足时也能自动清理,问题不大吧。不能全退就不全退呗,死不了。
后来又发生了一件事,让我对 Android 的 Activity 和内存机制又有不同的看法了。我同事有一台电信送的手机,配置很差,只有几百M内存,在上面跑我的程序,发现一个怪异的现象:我在程序里逐次打开了三个包含编辑框的Activity:A、B和C,并且这三个 Activity 里都输入了不同的内容,当前显示的是 C ;然后我按 HOME 键,打个电话,再用任务管理器切换回程序,这时程序显示的确实是原来的 Activity C,但上面编辑框的内容却消失了;再返回到 B、A ,发现 B、A 的编辑内容也消失了;也就是说,A、B、C的界面堆栈顺序还在,但界面的状态却丢失了。
世上哪有这么神奇的事,仔细一调试就知道了,原来在按 HOME 键打完电话回到程序时,程序的Activity的 onCreate 被再次调用,程序等于是重新创建了 Activity C。
继续研究发现,原来不仅仅是 Activity C,其它两个 Activity A 和 B 也是重新创建了。
继续再研究,发现其实连 Application 都重新创建了,所有全局变量已经清空。这正是我原来想要的退出效果,在我不需要的时候它出来了,够讽剌的。
至此真相大白,原来在按 HOME 键打电话时,由于内存不足,系统自动把我的程序结束了,结束前它会记录 Activity 堆栈,会调用 Activity 的 onSaveInstanceState 和 Application 的 onLowMemory 让程序有机会保存数据;当再次回到程序时,系统会自动重新创建 Application ,然后按堆栈顺序先恢复 Activity C;但这时 A 和 B 可能还没恢复,这就是说,我们平时以为 Activity A 和 B 在C后面的假设真的很假,其实并不存在,存在的只是一个堆栈信息;除了顶级 Activity,所有界面和全局变量都已经清空。
了解了这些之后,我发现之前做的退出什么的都是浮云了,相反我们搞退出不但没好处还会造成不应有的混乱。这种情况下,我们自己搞堆栈做程序退出真是没有任何意义。
最后我只好投降了,我的程序只搞假退出,再也不管真正退出了。我在 ROOT Activity 退出时会做个标记,下次进来时会自动重新清理和设置一些全局变量,这就算重启程序了。想真的退出程序?等谷歌的新 API 看有没退出接口再说吧,目前来说我觉得真的没必要。
顺便说一下程序崩溃,有一段时间我想利用崩溃机制退出程序,最后发现,崩溃机制跟 System.exit(0) 和 android.os.Process.killProcess 一样,只能结束当前 Activity,同时可能会引起当前或上一个 Activity 的重新创建触发 onCreate 事件,但不能清掉整个程序,也只好放弃。
转载自:
http://blog.csdn.net/huzgd/article/details/7459774