经过debug,我发现是应用在调用我们的一个全局变量的时候,这个全局变量为空了,但是我们明明是有设置,而且在不切换之前也是有值的
原因分析:
最后在网上查找了一下,原来在内存较少的时候,来回切换的时候gc 会去将一些内存释放掉的,全局变量会被重新设置为默认值,
模拟的方法:
1: 首先声明一个静态的全局变量类:
package com.example.kodulf.crashdemo; /** * Created by Kodulf on 2017/5/12. */ public class StaticClass { public static String staticString; public static int[] intArray; }
2: 创建一个MainActivitypackage com.example.kodulf.crashdemo; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); StaticClass.staticString = "hello"; //初始化静态类里面的数组,给一个很大的内存亮 StaticClass.intArray = new int[1024*1024*25]; //启动第二个Activity Intent intent = new Intent(this,SecondActivity.class); startActivity(intent); } }
3: 创建SecondActivitypackage com.example.kodulf.crashdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; public class SecondActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); Log.d("kodulf",""+StaticClass.staticString); //下面这里 // 在当前显示的是SecondActivity的时候切换到后台,然后再切换回来,在内存较少的情况下,会报错 // 在当前显示的是SecondActivity的时候切换到后台,还有一种让他直接报错的方法,就是通过一些内存管理软件,在当前显示的是SecondActivity的时候切换到后台,点击内存清理,然后再切换回来 就会报错了 Log.d("kodulf",""+StaticClass.intArray.length); } }
4: 最直接的模拟方法:
启动该应用,默认的会在MainActivity的时候初始化那个静态的int数组,然后会自动启动SecondActivity
这个时候将该应用切换到后台
找到一个内存管理的工具,例如360软件助手,进行内存清理,
再将该应用切换回来,就会直接报错了
解决办法:
将全局变量尽量使用常量,如果要涉及到修改的全局变量,那么最好不要直接食用
1: 可以使用sharepreference 去保存然后。
2: 或者在onSaveInstanceState的时候保存这个全局变量,onRestoreInstanceState 的时候再给这个全局变量重新赋值就好了。
package com.example.kodulf.crashdemo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Log.d("kodulf",""+StaticClass.staticString);
//下面这里
// 在当前显示的是SecondActivity的时候切换到后台,然后再切换回来,在内存较少的情况下,会报错
// 在当前显示的是SecondActivity的时候切换到后台,还有一种让他直接报错的方法,就是通过一些内存管理软件,在当前显示的是SecondActivity的时候切换到后台,点击内存清理,然后再切换回来 就会报错了
Log.d("kodulf",""+StaticClass.intArray.length);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("intArray",StaticClass.intArray);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
StaticClass.intArray = (int[])savedInstanceState.getSerializable("intArray");
}
}
+++++++++++++++++++++++++++++++++++++++++
参考:http://blog.csdn.net/hs_73/article/details/50911133
后期测试的时候,发现有个偶然现象,当应用被切换到后台一段时间再切换回来的时候会莫名的崩溃,而且在log的错误信息,云测以及友盟的错误列表上都没有发现有错误日志输出。确实是比较棘手,但这确实是应用的bug,无法忽视,但是这个问题又无法很容易的重现。后期查找资料分析一下,可能是跟这几个原因有关:
1.没有很正确的理解getContext() , getActivity() ,Activity.this ,getApplicationContext的区别以及用法,乱用导致:
2.应用被切换到后台以后,由于Android的内存回收机制,Activity切换到后台之后,由于内存不够,此Activity被系统回收了,一段时间之后回到该应用程序,Activity被重新实例化了。而Activity被系统销毁时,附属在该Activity的Fragment并没有被销毁,在Activity的onSaveInstanceState里面将Fragment状态保存起来了,所以Activity重新创建了,但是FragmentA和FragmentB还是之前的,而此时FragmentA和FragmentB所附属的Activity已经被系统回收了,这次再调用getActivity时返回了null,我们看看FragmentActivity源码中的onSaveInstanceState方法:
由上面源码可以看出,FragmentActivity确实在onSaveInstanceState方法里面将Fragment的状态保存了。 解决方法其实很简单,我们只要让FragmentActivity被系统回收的时候,不保存Fragment的状态即可,即在FragmentActivity中重写onSaveInstanceState方法,并且注释掉super.onSaveInstanceState(outState)就行了。
参考:http://www.cnblogs.com/liuling/p/2015-9-21-1.html
3.存在某些全局静态变量被释放回收掉,再次打开时,由于缺少值,在一些配置较低的终端上容易出现。4.还比如,从一个界面跳转到第二个界面时,存在传值,当在第二个界面时应用被切换到后台,当你再切换到前台时,在这第二个activity里,在其onResume()方法中做了数据访问用到了前一个界面的传值,当这个值已经被回收掉,这时就会crash掉了,多做些非空判断总归是有利无弊的。
造成这个问题的原因可能很多,以上是我个人的项目经验,仅代表个人观点,欢迎补充指正。