接触正式的android开发已经有一段时间了,项目的第一个版本终于快完成了。有一次自己在测试的时候,把自己的android项目切到后台,同时打开了几个应用之后重新切回到自己的app,发现报错了。经过排查,发现是自己的单例对象中的数据被释放掉了,也就是int变量的值 变成了0,string变量的值变成了null。
我的单例一开始是这样的(举例);
public class UserInfo { private static UserInfo userInfo = null; private int level; private UserInfo() { <span style="white-space:pre"> </span>} public static UserInfo getInstance() { if (null == userInfo) { userInfo = new UserInfo(); } return userInfo; } public void setLevel(int level){ this.level = level; } public int getLevel(){ return level; } }
这应该是一个比较普通的单例类,用来存储我们经常使用的变量,平时我的使用是没有问题的,在各个activity,fragment里都可以正常使用,如下面代码片段:
if(UserInfo.getInstance().getLevel() == 3){ //我们的代码块 }
但是,当我使用我的测试机(测试机是512m内存)进行测试的时候,首先把android应用切到后台,打开多个其他的app如qq等,再把我们的应用恢复到前台的时候,上面例子的代码块竟然没有进入,我通过打印调试发现getLevel()的值已经是0了,也就是被释放了。我google了一下,有些人在android上使用像我这样的单例是没问题的,而有些人则会说自己的单例被释放了,也就是和我的情况一样。可能是由于手机内存吃紧,我们单例对象存储的数据被迫被释放了。
下面就要找到这个问题的解决方法。
(1)使用android application ,这个方法本来我是想使用的,但是大概查了一下,例如这篇文章:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0204/2409.html
发现最好不要使用这种方法,甚至文章里写了都不要使用单例~~我自己试了一下,感觉问题依然存在。
(2)onSaveInstanceState() 和 onRestoreInstanceState(),当我发生这个问题的时候,都是android强制性的移除了我当前的activity,可能同时释放了我的单例对象中的数据。我也的确执行了onSaveInstanceState()函数,同时在切回来的时候执行了onRestoreInstanceState()重绘我的activity,那么我可以在onSaveInstanceState()
里存储我的单例数据,然后在onRestoreInstanceState()里对我的数据进行重新赋值。这样貌似也是可以的,但是,这样的话,单例用起来就太那啥了,感觉都不需要单例了。。
(3)使用SharedPreferences来进行存取数据的操作,当我们为数据赋值和取出数据的时候,不妨用下面的代码:
<span style="white-space:pre"> </span>public void setLevel(int level, Context context){ saveSharedPreferences(context, "level", level+""); this.level = level; } public int getLevel(Context context){ level = Integer.parseInt(Utils.readSharedPreferences(context, "level")); return level; }
<span style="white-space:pre"> </span>public static void saveSharedPreferences(Context context, String name, String data) { SharedPreferences sharedPreferences = context.getSharedPreferences("school_user_info", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString(name, data); editor.commit(); } public static String readSharedPreferences(Context context, String name) { SharedPreferences sharedPreferences = context.getSharedPreferences("school_user_info", Context.MODE_MULTI_PROCESS); return sharedPreferences.getString(name, ""); }
在为单例对象中的数据赋值的时候,把这个数据存放在preference中,使用的时候,再从preference中取出我的值,进行相应的操作,这样做的话,即使当我的单例被释放了,我依旧可以从preference中取出数据,这样做之后,我发现自己之前的bug就消失了,不会因为数据为空导致各种各样的错误了。
但是,仔细想一下,发现这样做的话单例模式在这里使用就略有多余,我直接存取preference就可以了,干嘛还要这样写呢?因为项目进度较为紧迫,我只好用(3)方法修改了一下我的代码保证了其没有这样的bug,但是这样做以我现在的眼光来看,并不是非常好,感觉造成了代码的多余。但是单例模式是我们工作中最常用到的设计模式了,在学校的时候我们就经常使用它,难道在android里就不能这样使用单例吗?我对此持怀疑态度。
不知道大家有没有遇到和我一样的问题,如果遇到了,又是如何解决的呢?该如何在android中使用单例模式呢?希望有好方法的同学能分享自己的看法~