虽然我们的程序在正式上线之前,都会经过严格的测试,从而保证程序的健壮性和良好的用户体验,但是,一个人的测试或者是几个人的测试团队,都不能和上万甚至数十万的用户相比。因此,前期刚上线的程序在用户手里被玩崩了,也是很常见的事,但是,如果我们不做特殊处理,系统自带的程序崩溃提示真的太吓人了,用户看到之后会不知所措,因此,我们需要一个解决方案,就是在程序即将崩溃的时候,给用户一个更加友好的提示,来告诉他,程序马上要崩溃了。

    就像是下面这样:


Android我们要友好的告诉用户,程序要崩溃了_ide

 这样是不是更加友好一点呢?

    下面讲解如何实现。

     如果要实现这种功能,我们需要关注的是Thread类里面的一个接口,UncaughtExceptionHandler,还有一个设置Thread.setDefaultUncaughtExceptionHandler(),这两个东西到底是干嘛的呢?

    UncaughtExceptionHandler 这个接口是当Thread因为未被捕获的异常而要被终止的时候,会被调用的回调接口。

    而Thread.setDefaultUncaughtExceptionHandler()这个方法,则是设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。

    因此,如果我们想自己处理程序要崩溃时的处理逻辑,我们只需要实现UncaughtExceptionHandler接口,并调用Thread.setDefaultUncaughtExceptionHandler()设置即可。

    下面是示例代码

    首先,先给出上面效果图中的Activity的代码

[java] 
​​view plain​​​
​​​copy​​​
​​​​​​
​​​​​





1. package com.example.exceptiondemo;
2.
3. import android.app.Activity;
4. import android.os.Bundle;
5. import android.view.View;
6.
7. public class MainActivity extends Activity {
8.
9. @Override
10. protected void onCreate(Bundle savedInstanceState) {
11. super.onCreate(savedInstanceState);
12. setContentView(R.layout.activity_main);
13. // 注册默认的未捕捉异常处理类
14. Thread.setDefaultUncaughtExceptionHandler(AppException
15. .getAppExceptionHandler());
16. this);
17.
18. }
19.
20. public void btn(View view) {
21. // 除零错误,程序会崩溃
22. int c = 1 / 0;
23. }
24.
25. }



在这段代码里面,我们故意写了一个会出现异常的操作,除零,因此只要点击按钮,程序就会崩溃。


下面,我们要自己实现接口,这里,我继承了Exception类。


[java]
​​view plain​​​
​​​copy​​​
​​​​​​
​​​​​





1. package com.example.exceptiondemo;
2.
3. import java.lang.Thread.UncaughtExceptionHandler;
4.
5. import android.app.Activity;
6. import android.app.AlertDialog;
7. import android.content.DialogInterface;
8. import android.content.DialogInterface.OnClickListener;
9. import android.os.Looper;
10. import android.widget.Toast;
11.
12. /**
13. *
14. * @ClassName: com.example.exceptiondemo.AppException
15. * @Description: 应用程序异常类:用于捕获异常
16. * @author zhaokaiqiang
17. * @date 2014-11-2 下午10:06:49
18. *
19. */
20.
21. public class AppException extends Exception implements UncaughtExceptionHandler {
22.
23. private static final long serialVersionUID = -6262909398048670705L;
24.
25. private String message;
26.
27. private Thread.UncaughtExceptionHandler mDefaultHandler;
28.
29. private AppException() {
30. super();
31. this.mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
32. }
33.
34. public AppException(String message, Exception excp) {
35. super(message, excp);
36. this.mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
37. }
38.
39. public String getMessage() {
40. return message;
41. }
42.
43. public void setMessage(String message) {
44. this.message = message;
45. }
46.
47. /**
48. * 获取APP异常崩溃处理对象
49. *
50. * @param context
51. * @return
52. */
53. public static AppException getAppExceptionHandler() {
54. return new AppException();
55. }
56.
57. @Override
58. public void uncaughtException(Thread thread, Throwable ex) {
59.
60. if (!handleException(ex) && mDefaultHandler != null) {
61. mDefaultHandler.uncaughtException(thread, ex);
62. }
63.
64. }
65.
66. /**
67. * 自定义异常处理
68. *
69. * @param ex
70. * @return true:处理了该异常信息;否则返回false
71. */
72. private boolean handleException(Throwable ex) {
73. if (ex == null) {
74. return false;
75. }
76.
77. final Activity activity = AppManager.getAppManager().currentActivity();
78.
79. if (activity == null) {
80. return false;
81. }
82.
83. new Thread() {
84. @Override
85. public void run() {
86. Looper.prepare();
87. "程序要崩了", Toast.LENGTH_SHORT).show();
88. new AlertDialog.Builder(activity).setTitle("提示")
89. false).setMessage("亲,程序马上崩溃了...")
90. "没关系", new OnClickListener() {
91. @Override
92. public void onClick(DialogInterface dialog,
93. int which) {
94. AppManager.getAppManager().exitApp(activity);
95. }
96. }).create().show();
97. Looper.loop();
98. }
99. }.start();
100.
101. return true;
102. }
103.
104. }



实现借口之后,我们需要在uncaughtException()方法里面处理自己的逻辑,我在这里面弹出对话框提示用户程序崩溃,这样,就比较友好一些。在代码里面的AppManager类是一个Activity的管理类,下面是代码





[java]
​​view plain​​​
​​​copy​​​
​​​​​​
​​​​​





1. package com.example.exceptiondemo;
2.
3. import java.util.Stack;
4.
5. import android.app.Activity;
6. import android.app.ActivityManager;
7. import android.content.Context;
8.
9. /**
10. *
11. * @ClassName: net.oschina.app.AppManager
12. * @Description: Activity管理类:用于管理Activity和退出程序
13. * @author zhaokaiqiang
14. * @date 2014-11-2 上午11:27:55
15. *
16. */
17. public class AppManager {
18.
19. private static Stack<Activity> activityStack;
20. private static AppManager instance;
21.
22. private AppManager() {
23. }
24.
25. /**
26. * 单一实例
27. */
28. public static AppManager getAppManager() {
29. if (instance == null) {
30. new AppManager();
31. }
32. return instance;
33. }
34.
35. /**
36. * 添加Activity到堆栈
37. */
38. public void addActivity(Activity activity) {
39. if (activityStack == null) {
40. new Stack<Activity>();
41. }
42. activityStack.add(activity);
43. }
44.
45. /**
46. * 获取当前Activity(堆栈中最后一个压入的)
47. */
48. public Activity currentActivity() {
49. Activity activity = activityStack.lastElement();
50. return activity;
51. }
52.
53. /**
54. * 结束当前Activity(堆栈中最后一个压入的)
55. */
56. public void finishActivity() {
57. Activity activity = activityStack.lastElement();
58. finishActivity(activity);
59. }
60.
61. /**
62. * 结束指定的Activity
63. */
64. public void finishActivity(Activity activity) {
65. if (activity != null) {
66. activityStack.remove(activity);
67. activity.finish();
68. null;
69. }
70. }
71.
72. /**
73. * 结束指定类名的Activity
74. */
75. public void finishActivity(Class<?> cls) {
76. for (Activity activity : activityStack) {
77. if (activity.getClass().equals(cls)) {
78. finishActivity(activity);
79. }
80. }
81. }
82.
83. /**
84. * 结束所有Activity
85. */
86. public void finishAllActivity() {
87. for (int i = 0, size = activityStack.size(); i < size; i++) {
88. if (null != activityStack.get(i)) {
89. activityStack.get(i).finish();
90. }
91. }
92. activityStack.clear();
93. }
94.
95. /**
96. * 退出应用程序
97. */
98. public void exitApp(Context context) {
99. try {
100. finishAllActivity();
101. ActivityManager activityMgr = (ActivityManager) context
102. .getSystemService(Context.ACTIVITY_SERVICE);
103. activityMgr.killBackgroundProcesses(context.getPackageName());
104. 0);
105. catch (Exception e) {
106. }
107. }
108. }


    Demo下载地址:

​https://github.com/ZhaoKaiQiang/ExceptionDemo​