您好,登錄后才能下訂單哦!
本文實例講述了Android編程實現(xiàn)項目中異常捕獲及對應(yīng)Log日志文件保存功能。分享給大家供大家參考,具體如下:
做程序開發(fā),肯定離不開與BUG打交道,更加離不開程序異常的出現(xiàn)。在開發(fā)的時候,我們可以通斷點調(diào)試,日志打印,異常捕獲工具等方式發(fā)現(xiàn)或處理程序中的Exception。那客戶在使用我們的應(yīng)用時,程序了問題,我們怎么可以知道呢?當然,我們可以加上友盟統(tǒng)計等第三方工具。另外還能怎么做呢?那就是把異常信息通過文檔地形式保存下來,如果用戶在使用的時候程序出了異常,可以讓用戶把對應(yīng)的日志信息發(fā)給我們或客服人員,更好的是在程序中做好處理,把日志發(fā)到指定服務(wù)器(程序中記得添加網(wǎng)絡(luò)權(quán)限哦)中,我們也可以拿到日志,我們就能發(fā)現(xiàn)問題,處理問題啦。
異常捕獲的關(guān)鍵代碼:
/** * UncaughtExceptionHandler:線程未捕獲異??刂破魇怯脕硖幚砦床东@異常的。 實現(xiàn)該接口并注冊為程序中的默認未捕獲異常處理 * 這樣當未捕獲異常發(fā)生時,就可以做些異常處理操作 例如:收集異常信息,發(fā)送錯誤報告 等。 * * @description: * @author ldm * @date 2016-4-18 上午11:31:19 */ public class MyExceptionHandler implements UncaughtExceptionHandler { // 上下文 private Context mContext; // 是否打開上傳 public boolean openUpload = true; // Log文件路徑 private static final String LOG_FILE_DIR = "log"; // log文件的后綴名 private static final String FILE_NAME = ".log"; private static MyExceptionHandler instance = null; // 系統(tǒng)默認的異常處理(默認情況下,系統(tǒng)會終止當前的異常程序) private UncaughtExceptionHandler mDefaultCrashHandler; private MyExceptionHandler(Context cxt) { // 獲取系統(tǒng)默認的異常處理器 mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler(); // 將當前實例設(shè)為系統(tǒng)默認的異常處理器 Thread.setDefaultUncaughtExceptionHandler(this); // 獲取Context,方便內(nèi)部使用 this.mContext = cxt.getApplicationContext(); } public synchronized static MyExceptionHandler create(Context cxt) { if (instance == null) { instance = new MyExceptionHandler(cxt); } return instance; } /** * 當程序中有未被捕獲的異常,系統(tǒng)將會自動調(diào)用#uncaughtException方法 * thread為出現(xiàn)未捕獲異常的線程,ex為未捕獲的異常,有了這個ex,我們就可以得到異常信息。 */ @Override public void uncaughtException(Thread thread, Throwable ex) { try { // 保存導出異常日志信息到SD卡中 saveToSDCard(ex); } catch (Exception e) { e.printStackTrace(); } finally { // 如果系統(tǒng)提供了默認的異常處理器,則交給系統(tǒng)去結(jié)束我們的程序,否則就由我們自己結(jié)束自己 Toast.makeText(mContext, "很抱歉,程序出錯,即將退出:\r\n" + ex.getLocalizedMessage(), Toast.LENGTH_LONG).show(); if (mDefaultCrashHandler != null) { mDefaultCrashHandler.uncaughtException(thread, ex); } else { ex.printStackTrace(); } } } /** * 保存文件到SD卡 * * @description: * @author ldm * @date 2016-4-18 上午11:37:17 */ private void saveToSDCard(Throwable ex) throws Exception { File file = FileUtil.getAppointFile(mContext.getPackageName() + File.separator + LOG_FILE_DIR, getDataTime("yyyy-MM-dd-HH-mm-ss") + FILE_NAME); PrintWriter pw = new PrintWriter(new BufferedWriter( new FileWriter(file))); // 導出發(fā)生異常的時間 pw.println(getDataTime("yyyy-MM-dd-HH-mm-ss")); // 導出手機信息 savePhoneInfo(pw); pw.println(); // 導出異常的調(diào)用棧信息 ex.printStackTrace(pw); pw.close(); } /** * 保存手機硬件信息 * * @description: * @author ldm * @date 2016-4-18 上午11:38:01 */ private void savePhoneInfo(PrintWriter pw) throws NameNotFoundException { // 應(yīng)用的版本名稱和版本號 PackageManager pm = mContext.getPackageManager(); PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES); pw.print("App Version: "); pw.print(pi.versionName); pw.print('_'); pw.println(pi.versionCode); pw.println(); // android版本號 pw.print("OS Version: "); pw.print(Build.VERSION.RELEASE); pw.print("_"); pw.println(Build.VERSION.SDK_INT); pw.println(); // 手機制造商 pw.print("Manufacturer: "); pw.println(Build.MANUFACTURER); pw.println(); // 手機型號 pw.print("Model: "); pw.println(Build.MODEL); pw.println(); } /** * 根據(jù)時間格式返回時間 * * @description: * @author ldm * @date 2016-4-18 上午11:39:30 */ private String getDataTime(String format) { SimpleDateFormat df = new SimpleDateFormat(format); return df.format(new Date()); } }
使用的時候,我們需要在Application中初始化:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); MyExceptionHandler.create(this); } }
在AndroidManifest.xml文件中注冊好Application:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ldm.exception" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.INTERNET" /> <application android:name="com.ldm.exception.MyApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.ldm.activity.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
注:更多關(guān)于Android Manifest權(quán)限控制文件的說明可點擊此處查看Android權(quán)限操作說明
文件上傳的方法有寫好,但是沒有具體實現(xiàn),比如一但有日志文件就上傳或是日志文件達到一定大小再上傳,這就要根據(jù)實際情況來定啦。
當我們應(yīng)用出現(xiàn)異常時,在手機文件夾中存在我們應(yīng)用包名的文件夾,里面就有日志文件。
附:完整Demo點擊此處本站下載。
更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android調(diào)試技巧與常見問題解決方法匯總》、《Android開發(fā)入門與進階教程》、《Android基本組件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android布局layout技巧總結(jié)》及《Android控件用法總結(jié)》
希望本文所述對大家Android程序設(shè)計有所幫助。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。