Android中不管是使用public static 定义全局变量,还是使用Application类进行全局变量的定义,都不能算作是实际意义上的全局变量,他们都会因为Activity被系统释放而造成传值失败。
最近在做一个简单的APP应用,其中专门写一个http访问的线程类,所有的http访问都会调用此类进行访问,每次http访问都会要发送用户名和密码,所以最初的考虑是将用户名和密码定义为pubic static存放到一个公共类中,但是偶尔会出现获取用户名密码为空的情况,一旦为空,就一直为空。
后来看到有人说使用Application类进行存储,但是问题仍然存在。
原因就是因为Activity可能会因为一些原因被Kill掉,全局变量也会被释放掉。
以下参考网友的博客:
Android开发中一般都是使用Intent给Activity传参。有时需要传复杂对象时,我们会倾向于用全局变量(静态变量或Application属性)。但其实这样做是有隐患的,跟Activity的生命周期有关,正好最近遇到这个问题,在这里写一下。
大概情况是这样的:ActivityA中点击按钮启动ActivityB,同时要传一个大数据对象,懒得对这个对象进行序列化,于是就直接搞了个全局变量ActivityB.param写了进去,在ActivityB.onCreate里读取并显示信息,编译运行一切正常。这样过了大半个月似乎也没发现什么问题。直到有一天发给客户使用后,在友盟后台看到了空指针错误,仔细分析堆栈代码,错误就在ActivityB.onCreate里读取全局变量时发生,也就是全局变量返回了空!
全局变量为空一般就是由于内存不足进程被KILL过重新创建了。按常理分析,ActivityA在给ActivityB.param赋值后会立即启动ActivityB,这过程很短,进程不可能这么快被KILL,因此理论上ActivityB.onCreate中应该能读取到ActivityB.param的。
实际上,在ActivityA给ActivityB.param赋值启动ActivityB后,ActivityB.onCreate确实是能读取到ActivityB.param的;但是,ActivityB并不能保证永远在前台,一旦ActivityB所在任务被切到后台(如有电话打进来了),系统就可以在内存不足时将ActivityB所在的进程KILL掉;而当ActivityB所在任务被切回前台(如电话打完了),这时系统会自动重新恢复ActivityB,这时全局变量自然就没了。
有人说我不用静态变量,用Application的属性来存全局参数,是不是就可以避免这个问题了呢?其实也是不行的,因为进程被KILL再恢复后,Application对象也是销毁重建了的;安卓系统并不保证会在KILL进程前给程序发通知,因此我们也无法在Application里保存恢复全局变量。
另外,全局变量也不能记录安卓的界面Context相关的类(如Activity、View),因为安卓系统自动管理这些类,记录它们会导致引用计数增加无法释放的内存泄露问题;如果一定要记录,则应该使用弱引用WeakReference。
总之安卓开发中是不推荐用全局变量传参的。最好的办法还是按照安卓的开发规范,完全使用Intent进行传参,因为系统在KILL进程前会自动保存Activity堆栈,同时保存相关的Intent参数,并自动进行恢复。如果非要用全局变量,则至少必须在读取全局变量处理时判断是否为空,避免程序出错崩溃;同时最好在onPause时自行保存数据以便被KILL后恢复。
但是我觉得全局变量也不是一无是处完全不能用,主要是要理解并避开安卓进程生命周期中全局变量的变化。例如用全局变量来记录自己写的全局处理类(如工厂类、类注册器等),只要注意在被进程KILL后做好恢复工作,是完全可以的。