在我们开发Android应用程序的时候总是难免遇到程序崩溃的问题:(很抱歉,“××”已停止运行。)
每次看到这个问题心都是哇凉哇凉的
一般遇到这样问题,有两种可能:
1、自己的代码写得不够精密,导致异常。(
好好面壁思过去)
2、当应用程序被用户使用home键退至后台,而又由于内存不足,导致内存被释放,然后用户再次打开这个App,就有可能导致报错,而且一般是空指针问题,原因:
(引用一下别人话)
也就是在系统直接恢复B的时候,但是,B里面使用到了A帮其初始化的一些数据,但是,是直接恢复B的(没有经过A),导致那些数据为Null,于是报错~~
但是,系统却说,这锅我不背,
大致问题描述就是这样了,下面我们共同解决问题:
针对原因一、二的解决方式
由于两个问题的直接导致结果是程序异常崩溃,因此,我们需要两个步骤去进行处理:
1. 捕捉异常
2. 对异常进行自定义处理
1. 捕捉异常
详情可以去百度or谷歌“Android捕捉异常”,这里就不展开细说,只是说说大概流程:
创建自定义Application捕捉异常(MyApplication.java)
/** * Created by Jinxiong.Xie on /1/18 11:54. * 邮箱:173500512@ */
public class MyApplication extends Application {
private static MyApplication mMyApplication;
@Override
public void onCreate() {
super.onCreate();
initData();
}
private void initData() {
mMyApplication = this;
//监视应用异常
CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(getApplicationContext());
}
public static final MyApplication getInstance() {
return mMyApplication;
}
}
别忘了在AndroidManifest.xml中进行配置:
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
异常的监视与处理(CrashHandler.java)
/** * 捕捉异常并处理 * Created by Jinxiong.Xie on /1/18 11:59. * 邮箱:173500512@ */
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static final String TAG = "CrashHandler";
// CrashHandler 实例
private static CrashHandler INSTANCE = new CrashHandler();
// 程序的 Context 对象
private Context mContext;
// 系统默认的 UncaughtException 处理类
private Thread.UncaughtExceptionHandler mDefaultHandler;
/** * 保证只有一个 CrashHandler 实例 */
private CrashHandler() {
}
/** * 获取 CrashHandler 实例 ,单例模式 */
public static CrashHandler getInstance() {
return INSTANCE;
}
/** * 初始化 * *@param context */
public void init(Context context) {
mContext = context;
// 获取系统默认的 UncaughtException 处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// 设置该 CrashHandler 为程序的默认处理器
Thread.setDefaultUncaughtExceptionHandler(this);
Log.d("TEST", "Crash:init");
}
/** * 当 UncaughtException 发生时会转入该函数来处理 */
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "error : ", e);
}
//退出程序
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
}
/** * 自定义错误处理,收集错误信息,发送错误报告等操作均在此完成 * *@param ex *@return true:如果处理了该异常信息;否则返回 false */
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
// 异常的自定义处理
// 日志书写之类的。。
new Thread() {
@Override
public void run() {
Looper.prepare();
//相关UI处理
Looper.loop();
}
}.start();
return true;
}
}
2. 对异常进行自定义处理
这里处理的方式就很多了,例如日志的上传、弹出一个自定义的dialog提示用户程序异常、重启App之类的,而在这里,我要讲的是“重启App”的,但是并不是真正的关闭App,然后对其进行重启,因为假如你关闭App再进行打开的话,用户会看到一个闪烁的效果(程序背景变暗–>程序关闭回到桌面–>程序自动打开),这样无疑对于用户体验并不友好,我使用的方式是对于App进行初始化,然后跳转到App最开始的页面,这样普通用户就会感觉App并没有崩溃,只是卡了一下,然后重新启动了。示例代码:
new Thread() {
@Override
public void run() {
Looper.prepare();
// 异常的自定义处理
MyApplication.getInstance().initData();//对于App进行初始化(因为一般我们都会在Application中进行初始化数据,假如仅仅是跳转到App最开始的页面,这样可能会导致报Null错误)
Intent intent = new Intent(mContext, AActivity.class);//跳转到App最开始的页面
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
Looper.loop();
}
}.start();
针对原因二的解决方式
由于原因二的崩溃是由于数据没初始化的原因导致,因此,我们只要将这些数据保存or初始化即可,做法有以下两种:
因为Activity在非正常关闭的时候,会调用onSaveInstanceState()进行保存数据,当Activity重新打开的时候,会调用onRestoreInstanceState()重新初始化数据,因此,我们可以在这两个方法内相应地保存数据和恢复数据即可解决数据为null的问题。
Activity在重新启动的时候,仍然会调用onCreate()方法初始化,因此,我们仍然可以在onCreate()中初始化相应的数据,但是,有一点注意的是,在里面初始化的数据不能涉及到在于其它页面初始化的数据,简单地说就是——在重新启动BActivity的时候,我们不能调用AActivity里面初始化的数据or一些全局的变量,否则程序仍然会崩溃。
参考: