为何Android开发中不推荐使用static全局变量传参
2014-02-18 18:11
483 查看
原文链接
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后做好恢复工作,是完全可以的。
建议:1. 传递数据使用intent
2. 保存状态值,比如登陆状态用SharedPreference
3. 其他数据可以用SQLite / 文件 存储起来
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后做好恢复工作,是完全可以的。
建议:1. 传递数据使用intent
2. 保存状态值,比如登陆状态用SharedPreference
3. 其他数据可以用SQLite / 文件 存储起来
相关文章推荐
- [Android] View控件显示隐藏动画效果
- Android如何加载硬件OpenGLES库
- 【android】apk逆向
- Android 新浪微博第三方登录
- libcurl在android下的移植、编译与测试
- Android SMS(二)—— 读取短信保存到 SQLite
- android 日期控件
- Android SMS(一) —— 读取短信
- Eclipse中跟踪调试Android Framework源代码
- android 制作.9.png图片
- Android Contacts(一)—— 读取联系人
- [Android开发常见问题-24] Android 的 SurfaceView 双缓冲应用
- Android多媒体开发 Pro Android Media 第一章 Android图像编程入门 1
- Android Contacts(二)—— SMS 短信 与 Contacts 联系人关联
- Android仿360悬浮框
- Android中Activity启动模式详解
- android4.1修改界面边缘阴影
- 新建的android项目,没有自动生成R.java 文件
- Android中dp转px
- Android support library 不能创建项目 的问题解决办法