日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android UncaughtExceptionHandler 全局异常监控

發(fā)布時間:2025/3/17 Android 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android UncaughtExceptionHandler 全局异常监控 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2019獨角獸企業(yè)重金招聘Python工程師標準>>>

一、全局捕獲異常

為了解決這樣的問題,我們需要能夠及時的捕獲異常,但要捕獲的地方是在太多,因此,我們需要進行全局性的異常捕獲,那么如何捕獲全局異常呢?

答案是UncaughtExceptionHandler+Thread.setDefaultUncaughtExceptionHandler

?

1.UncaughtExceptionHandler是未捕獲異常的處理接口,該類率先捕獲異常

?UncaughtExceptionHandler:?線程未捕獲異常控制器是用來處理未捕獲異常的。??如果程序出現(xiàn)了未捕獲異常默認情況下則會出現(xiàn)強行關閉對話框?實現(xiàn)該接口并注冊為程序中的默認未捕獲異常處理??這樣當未捕獲異常發(fā)生時,就可以做些異常處理操作?例如:收集異常信息,發(fā)送錯誤報告?等。

二、代碼實戰(zhàn)

對于這個接口,我們需要進行實現(xiàn)

public?class?AppCrashHandler?implements?UncaughtExceptionHandler?{private?Context?mContext;private?Thread.UncaughtExceptionHandler?mDefaultHandler;/**防止多線程中的異常導致讀寫不同步問題的lock**/private?Lock?lock?=?null;/**本地保存文件日志**/private?final?String?CRASH_REPORTER_EXTENSION?=?".crash";/**日志tag**/private?final?String?STACK_TRACE?=?"logStackTrance";/**保存文件名**/private?final?String?crash_pref_path?="app_crash_pref.xml";private?static?final?String?OOM?=?"java.lang.OutOfMemoryError";private?static?final?String?HPROF_FILE_PATH?=?Environment.getExternalStorageDirectory().getPath()?+?"/data_crash.hprof"private?AppCrashHandler(){lock?=?new?ReentrantLock(true);}/***?獲得單例對象*?@param?context*?@return?AppCrashHandler*/public?static?AppCrashHandler?shareInstance(Context?context){AppCrashHandler?crashhandler?=?AppCrashHandler.InstanceHolder.crashHandler;crashhandler.initCrashHandler(context);return?crashhandler;}/***?使用初始化方法初始化,防止提前初始化或者重復初始化*?@param?cxt*/private?void?initCrashHandler(Context?cxt){if(!hasInitilized()){mDefaultHandler?=?Thread.getDefaultUncaughtExceptionHandler();Thread.setDefaultUncaughtExceptionHandler(this);mContext?=?cxt;?}}public?interface?InstanceHolder{public?static?AppCrashHandler?crashHandler?=?new?AppCrashHandler();}public?static?boolean?isOOM(Throwable?throwable){??Log.d(TAG,?"getName:"?+?throwable.getClass().getName());??if(OOM.equals(throwable.getClass().getName())){??return?true;??}else{??Throwable?cause?=?throwable.getCause();??if(cause?!=?null){??return?isOOM(cause);??}??return?false;??}??}??@Overridepublic?void?uncaughtException(Thread?thread,?Throwable?ex)?{if(isOOM(throwable)){??try?{??Debug.dumpHprofData(HPROF_FILE_PATH);}?catch?(Exception?e)?{??Log.e(TAG,?"couldn’t?dump?hprof",?e);??}??}??if?(!handleExceptionMessage(ex)?&&?mDefaultHandler?!=?null)?{??//?如果用戶沒有處理則讓系統(tǒng)默認的異常處理器來處理??mDefaultHandler.uncaughtException(thread,?ex);??}?else?{??try?{??Thread.sleep(3000);??}?catch?(InterruptedException?e)?{??Log.e(STACK_TRACE,?"Error?:?",?e);??}??android.os.Process.killProcess(android.os.Process.myPid());??System.exit(10);??}??}/**?*?自定義錯誤處理,收集錯誤信息?發(fā)送錯誤報告等操作均在此完成.?開發(fā)者可以根據(jù)自己的情況來自定義異常處理邏輯?*?@param?ex?*?@return?true:如果處理了該異常信息;否則返回false?*/??private?boolean?handleExceptionMessage(Throwable?ex)?{??if?(ex?==?null)?{??return?false;??}??//?使用Toast來顯示異常信息??new?Thread()?{??@Override??public?void?run()?{??//?Toast?顯示需要出現(xiàn)在一個線程的消息隊列中??Looper.prepare();??Toast.makeText(mContext,?"程序出錯啦,即將退出",?Toast.LENGTH_LONG).show();??Looper.loop();??}??}.start();??String?fileName?=?mContext.getPackageName()+"-"+"appCrash-Exception"+?CRASH_REPORTER_EXTENSION;??String?crashFileName?=?saveExceptionToFile(ex,fileName);?SharedPreferences.Editor?editor?=?mContext.getSharedPreferences(crash_pref_path?,?Context.MODE_PRIVATE).edit();editor.putString(STACK_TRACE,?crashFileName);editor.commit();Log.d(STACK_TRACE,?"errorLogPath="+crashFileName);return?true;??}??/***?是否已初始化*?@return*/public?boolean?hasInitilized(){return?mContext!=null;}/**?*?保存錯誤信息到文件中?*?@param?ex?*?@return?*?@throws?IOException?*/??private?String?saveExceptionToFile(Throwable?ex,String?fileName)?{??File?saveFile?=?null;PrintWriter?printWriter?=?null;??try?{lock.tryLock();if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){File?sdCardDir?=?Environment.getExternalStorageDirectory();//獲取SDCard目錄saveFile?=?new?File(sdCardDir,?fileName);}else{saveFile?=new?File(mContext.getFilesDir(),fileName);}if(!saveFile.exists()){saveFile.createNewFile();}printWriter?=?new?PrintWriter(saveFile);String?result?=?formatException(ex);printWriter.write(result);printWriter.flush();Log.e("CrashException",?result);}catch(Exception?e){e.printStackTrace();}?finally{if(printWriter!=null){printWriter.close();}lock.unlock();}return?saveFile!=null?saveFile.getAbsolutePath():null;??}??/***?格式化異常信息*?@param?e*?@return*/@SuppressLint("SimpleDateFormat")private??String??formatException(Throwable?e){StringBuilder?sb?=?new?StringBuilder();StackTraceElement[]?stackTrace?=?e.getStackTrace();SimpleDateFormat?sdf?=?new?SimpleDateFormat("yyyy-MM-dd?HH:mm:ss");if?(stackTrace!=null){String??timeStramp?=??sdf.format(new?Date(System.currentTimeMillis()));String?format?=?String.format("DateTime:%s\nExceptionName:%s\n\n",timeStramp,e.getLocalizedMessage());sb.append(format);for?(int?i?=?0;?i?<?stackTrace.length;?i++)?{StackTraceElement?traceElement?=?stackTrace[i];String? fileName? =?traceElement.getFileName();int? lineNumber? =?traceElement.getLineNumber();String? methodName? =?traceElement.getMethodName();String? className?=?traceElement.getClassName();sb.append(String.format("%s\t%s[%d].%s?\n",className,fileName,lineNumber,methodName));}sb.append(String.format("\n%s",e.getMessage()));Writer?stringWriter?=?new?StringWriter();PrintWriter?pw?=?new?PrintWriter(stringWriter);e.printStackTrace(pw);pw.flush();pw.close();sb.append("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");sb.append(stringWriter.toString());}return?sb.toString();} }

這里只保存了文件,一般來說,當app第二次啟動時我們需要將該文件上傳到網(wǎng)絡,時間不是很充裕,這里上傳暫時不貼代碼了,時間充裕的話會及時補充,請保持關注吧

?

2.初始化,監(jiān)聽全局異常信息,這里需要繼承Application,并替換系統(tǒng)默認的Application

public?class?BaseApplication?extends?Application? {private??static?BaseApplication?instance?=?null;private?AppCrashHandler?appCrashHandler?=?null;@Overridepublic?void?onCreate()?{synchronized?(this){if(instance==null){instance?=?this;}appCrashHandler?=??AppCrashHandler.shareInstance(instance);}super.onCreate();}@Overridepublic?void?onConfigurationChanged(Configuration?newConfig)?{super.onConfigurationChanged(newConfig);}}

修改清單文件

<applicationandroid:name="com.hali.luya.unitest.BaseApplication?"android:hardwareAccelerated="true"android:icon="@drawable/app_logo"android:logo="@drawable/app_logo"android:label="@string/app_name"android:configChanges="locale|keyboard|screenSize"android:theme="@style/Theme.AppBaseTheme"?><!---?..這里省略一大堆代碼..?----></Application>

?

三、騰訊Bugly

騰訊有一個bugly產(chǎn)品可以實現(xiàn)crash收集和處理,當然也可以同時使用UncaughtExceptionHandler,因為騰訊bugly雖然也實現(xiàn)了UncaughtExceptionHandler該回調(diào),但騰訊bugly在捕獲異常的同時也會調(diào)用你自己的UncaughtExceptionHandler。

?

目前騰訊的bugly不支持回調(diào),但我申請到了騰訊的內(nèi)測版支持回調(diào)。

public?class?BaseApplication?extends?Application? {private??static?Application?instance?=?null;private?AppCrashHandler?appCrashHandler?=?null;private?final?String?APP_CONTEXT_TAG?=?"appContext";@Overridepublic?void?onCreate()?{synchronized?(this){if(instance==null){instance?=?this;}appCrashHandler?=??AppCrashHandler.shareInstance(instance);UserStrategy?strategy?=?new?UserStrategy(instance);?//App的策略Beanstrategy.setAppChannel(getPackageName());?????//設置渠道strategy.setAppVersion(getVersion());??????//App的版本strategy.setAppReportDelay(1000);??//設置SDK處理延時,毫秒strategy.setDeviceID(GlobalUtil.getInstance().getDeviceID(instance));strategy.setCrashHandleCallback(new?AppCrashHandleCallback());CrashReport.initCrashReport(instance,?"900001335",?true,?strategy);?//自定義策略生效,必須在初始化SDK前調(diào)用CrashReport.?setUserId("BBDTEK");}//shutDownLog();super.onCreate();}@Overridepublic?void?onConfigurationChanged(Configuration?newConfig)?{super.onConfigurationChanged(newConfig);}/***?獲取版本號*?@return?當前應用的版本號*/public?String?getVersion()?{try?{PackageManager?manager?=?this.getPackageManager();PackageInfo?info?=?manager.getPackageInfo(this.getPackageName(),?0);String?version?=?info.versionName;return?this.getString(R.string.app_version)?+?version;}?catch?(Exception?e)?{e.printStackTrace();return?this.getString(R.string.app_version);}}private?class?AppCrashHandleCallback?extends?CrashHandleCallback?//bugly回調(diào){@Overridepublic?synchronized?Map<String,?String>?onCrashHandleStart(int?crashType,?String?errorType,?String?errorMessage,?String?errorStack){String?crashTypeName?=?null;switch?(crashType){case?CrashHandleCallback.CRASHTYPE_JAVA_CATCH:crashTypeName?=?"JAVA_CATCH";break;case?CrashHandleCallback.CRASHTYPE_JAVA_CRASH:crashTypeName?=?"JAVA_CRASH";break;case?CrashHandleCallback.CRASHTYPE_NATIVE:crashTypeName?=?"JAVA_NATIVE";break;case?CrashHandleCallback.CRASHTYPE_U3D:crashTypeName?=?"JAVA_U3D";break;default:{crashTypeName?=?"unknown";}}Log.e(APP_CONTEXT_TAG,?"Crash?Happen?Type:"?+?crashType?+?"?TypeName:"?+?crashTypeName);Log.e(APP_CONTEXT_TAG,?"errorType:"?+?errorType);Log.e(APP_CONTEXT_TAG,?"errorMessage:"?+?errorMessage);Log.e(APP_CONTEXT_TAG,?"errorStack:"?+?errorStack);Map<String,?String>?userDatas?=?super.onCrashHandleStart(crashType,?errorType,?errorMessage,?errorStack);if?(userDatas?==?null){userDatas?=?new?HashMap<String,?String>();}userDatas.put("DEBUG",?"TRUE");return?userDatas;}}/***?關閉重要信息的日志*/private?void?shutDownLog(){LogUtils.allowE?=?false;LogUtils.allowI?=?false;LogUtils.allowV?=?false;LogUtils.allowW?=?false;LogUtils.allowWtf?=?false;LogUtils.allowD?=?false;} }

?

?

?

try ?doing it

轉(zhuǎn)載于:https://my.oschina.net/ososchina/blog/351613

總結(jié)

以上是生活随笔為你收集整理的Android UncaughtExceptionHandler 全局异常监控的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。