1+ package com .jingewenku .abrahamcaijin .commonutil ;
2+
3+ import android .content .Context ;
4+ import android .content .pm .PackageInfo ;
5+ import android .content .pm .PackageManager ;
6+ import android .os .Build ;
7+ import android .os .Environment ;
8+ import android .os .Looper ;
9+ import android .util .Log ;
10+ import android .widget .Toast ;
11+
12+ import java .io .*;
13+ import java .lang .reflect .Field ;
14+ import java .text .DateFormat ;
15+ import java .text .SimpleDateFormat ;
16+ import java .util .Date ;
17+ import java .util .HashMap ;
18+ import java .util .Locale ;
19+ import java .util .Map ;
20+
21+
22+ /**
23+ * @Description:主要功能:UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
24+ * @Prject: CommonUtilLibrary
25+ * @Package: com.jingewenku.abrahamcaijin.commonutil
26+ * @author: AbrahamCaiJin
27+ * @date: 2017年06月01日 10:49
28+ * @Copyright: 个人版权所有
29+ * @Company:
30+ * @version: 1.0.0
31+ */
32+
33+ /*
34+ * public class AndroidUtilsApplication extends Application {
35+ * public void onCreate() {
36+ * super.onCreate();
37+ * //崩溃处理
38+ * CrashHandlerUtil crashHandlerUtil = CrashHandlerUtil.getInstance();
39+ * crashHandlerUtil.init(this);
40+ * crashHandlerUtil.setCrashTip("很抱歉,程序出现异常,即将退出!");
41+ * }
42+ * }
43+ */
44+
45+ public class CrashHandlerUtil implements Thread .UncaughtExceptionHandler {
46+
47+ public static final String TAG = "CrashHandlerUtil" ;
48+
49+ //系统默认的UncaughtException处理类
50+ private Thread .UncaughtExceptionHandler mDefaultHandler ;
51+ //CrashHandler实例
52+ private static CrashHandlerUtil INSTANCE = new CrashHandlerUtil ();
53+ //程序的Context对象
54+ private Context mContext ;
55+ //用来存储设备信息和异常信息
56+ private Map <String , String > infos = new HashMap <>();
57+
58+ //用于格式化日期,作为日志文件名的一部分
59+ private DateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd-HH-mm-ss" , Locale .CHINA );
60+ private String crashTip = "很抱歉,程序出现异常,即将退出!" ;
61+
62+ public String getCrashTip () {
63+ return crashTip ;
64+ }
65+
66+ public void setCrashTip (String crashTip ) {
67+ this .crashTip = crashTip ;
68+ }
69+
70+ /**
71+ * 保证只有一个CrashHandler实例
72+ */
73+ private CrashHandlerUtil () {
74+ }
75+
76+ /**
77+ * 获取CrashHandler实例 ,单例模式
78+ *
79+ * @return 单例
80+ */
81+ public static CrashHandlerUtil getInstance () {
82+ return INSTANCE ;
83+ }
84+
85+ /**
86+ * 初始化
87+ *
88+ * @param context 上下文
89+ */
90+ public void init (Context context ) {
91+ mContext = context ;
92+ //获取系统默认的UncaughtException处理器
93+ mDefaultHandler = Thread .getDefaultUncaughtExceptionHandler ();
94+ //设置该CrashHandler为程序的默认处理器
95+ Thread .setDefaultUncaughtExceptionHandler (this );
96+ }
97+
98+ /**
99+ * 当UncaughtException发生时会转入该函数来处理
100+ *
101+ * @param thread 线程
102+ * @param ex 异常
103+ */
104+ @ Override
105+ public void uncaughtException (Thread thread , Throwable ex ) {
106+ if (!handleException (ex ) && mDefaultHandler != null ) {
107+ //如果用户没有处理则让系统默认的异常处理器来处理
108+ mDefaultHandler .uncaughtException (thread , ex );
109+ } else {
110+ try {
111+ Thread .sleep (3000 );
112+ } catch (InterruptedException e ) {
113+ Log .e (TAG , "error : " , e );
114+ e .printStackTrace ();
115+ }
116+ //退出程序
117+ AppManager .getAppManager ().exitApp ();
118+ }
119+ }
120+
121+ /**
122+ * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
123+ *
124+ * @param throwable 异常
125+ * @return true:如果处理了该异常信息;否则返回false.
126+ */
127+ private boolean handleException (final Throwable throwable ) {
128+ if (throwable == null ) {
129+ return false ;
130+ }
131+ //使用Toast来显示异常信息
132+ new Thread () {
133+ @ Override
134+ public void run () {
135+ Looper .prepare ();
136+ throwable .printStackTrace ();
137+ Toast .makeText (mContext , getCrashTip (), Toast .LENGTH_LONG ).show ();
138+ Looper .loop ();
139+ }
140+ }.start ();
141+ //收集设备参数信息
142+ collectDeviceInfo (mContext );
143+ //保存日志文件
144+ saveCrashInfo2File (throwable );
145+ return true ;
146+ }
147+
148+ /**
149+ * 收集设备参数信息
150+ *
151+ * @param ctx 上下文
152+ */
153+ public void collectDeviceInfo (Context ctx ) {
154+ try {
155+ PackageManager pm = ctx .getPackageManager ();
156+ PackageInfo pi = pm .getPackageInfo (ctx .getPackageName (), PackageManager .GET_ACTIVITIES );
157+ if (pi != null ) {
158+ String versionName = pi .versionName == null ? "null" : pi .versionName ;
159+ String versionCode = pi .versionCode + "" ;
160+ infos .put ("versionName" , versionName );
161+ infos .put ("versionCode" , versionCode );
162+ }
163+ } catch (PackageManager .NameNotFoundException e ) {
164+ Log .e (TAG , "an error occured when collect package info" , e );
165+ }
166+ Field [] fields = Build .class .getDeclaredFields ();
167+ for (Field field : fields ) {
168+ try {
169+ field .setAccessible (true );
170+ infos .put (field .getName (), field .get (null ).toString ());
171+ Log .d (TAG , field .getName () + " : " + field .get (null ));
172+ } catch (Exception e ) {
173+ Log .e (TAG , "an error occured when collect crash info" , e );
174+ }
175+ }
176+ }
177+
178+ /**
179+ * 保存错误信息到文件中
180+ *
181+ * @param ex 异常
182+ * @return 返回文件名称, 便于将文件传送到服务器
183+ */
184+ private String saveCrashInfo2File (Throwable ex ) {
185+
186+ StringBuffer sb = new StringBuffer ();
187+ for (Map .Entry <String , String > entry : infos .entrySet ()) {
188+ String key = entry .getKey ();
189+ String value = entry .getValue ();
190+ sb .append (key + "=" + value + "\n " );
191+ }
192+
193+ Writer writer = new StringWriter ();
194+ PrintWriter printWriter = new PrintWriter (writer );
195+ ex .printStackTrace (printWriter );
196+ Throwable cause = ex .getCause ();
197+ while (cause != null ) {
198+ cause .printStackTrace (printWriter );
199+ cause = cause .getCause ();
200+ }
201+ printWriter .close ();
202+ String result = writer .toString ();
203+ sb .append (result );
204+ try {
205+ long timestamp = System .currentTimeMillis ();
206+ String time = formatter .format (new Date ());
207+ String fileName = "crash-" + time + "-" + timestamp + ".log" ;
208+ if (Environment .getExternalStorageState ().equals (Environment .MEDIA_MOUNTED )) {
209+ String path = Environment .getExternalStorageDirectory ().getPath () + "/crash/" ;
210+ AppLogMessageMgr .d ("path=" + path );
211+ File dir = new File (path );
212+ if (!dir .exists ()) {
213+ dir .mkdirs ();
214+ }
215+ FileOutputStream fos = new FileOutputStream (path + fileName );
216+ fos .write (sb .toString ().getBytes ());
217+ fos .close ();
218+ }
219+ return fileName ;
220+ } catch (Exception e ) {
221+ Log .e (TAG , "an error occured while writing file..." , e );
222+ }
223+ return null ;
224+ }
225+
226+ }
0 commit comments