Android編程實現(xiàn)項目中異常捕獲及對應(yīng)Log日志文件保存功能
本文實例講述了Android編程實現(xiàn)項目中異常捕獲及對應(yīng)Log日志文件保存功能。分享給大家供大家參考,具體如下:
做程序開發(fā),肯定離不開與BUG打交道,更加離不開程序異常的出現(xiàn)。在開發(fā)的時候,我們可以通斷點調(diào)試,日志打印,異常捕獲工具等方式發(fā)現(xiàn)或處理程序中的Exception。那客戶在使用我們的應(yīng)用時,程序了問題,我們怎么可以知道呢?當(dāng)然,我們可以加上友盟統(tǒng)計等第三方工具。另外還能怎么做呢?那就是把異常信息通過文檔地形式保存下來,如果用戶在使用的時候程序出了異常,可以讓用戶把對應(yīng)的日志信息發(fā)給我們或客服人員,更好的是在程序中做好處理,把日志發(fā)到指定服務(wù)器(程序中記得添加網(wǎng)絡(luò)權(quán)限哦)中,我們也可以拿到日志,我們就能發(fā)現(xiàn)問題,處理問題啦。
異常捕獲的關(guān)鍵代碼:
/** * UncaughtExceptionHandler:線程未捕獲異??刂破魇怯脕硖幚砦床东@異常的。 實現(xiàn)該接口并注冊為程序中的默認(rèn)未捕獲異常處理 * 這樣當(dāng)未捕獲異常發(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)默認(rèn)的異常處理(默認(rèn)情況下,系統(tǒng)會終止當(dāng)前的異常程序) private UncaughtExceptionHandler mDefaultCrashHandler; private MyExceptionHandler(Context cxt) { // 獲取系統(tǒng)默認(rèn)的異常處理器 mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler(); // 將當(dāng)前實例設(shè)為系統(tǒng)默認(rèn)的異常處理器 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; } /** * 當(dāng)程序中有未被捕獲的異常,系統(tǒng)將會自動調(diào)用#uncaughtException方法 * thread為出現(xiàn)未捕獲異常的線程,ex為未捕獲的異常,有了這個ex,我們就可以得到異常信息。 */ @Override public void uncaughtException(Thread thread, Throwable ex) { try { // 保存導(dǎo)出異常日志信息到SD卡中 saveToSDCard(ex); } catch (Exception e) { e.printStackTrace(); } finally { // 如果系統(tǒng)提供了默認(rèn)的異常處理器,則交給系統(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))); // 導(dǎo)出發(fā)生異常的時間 pw.println(getDataTime("yyyy-MM-dd-HH-mm-ss")); // 導(dǎo)出手機信息 savePhoneInfo(pw); pw.println(); // 導(dǎo)出異常的調(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),比如一但有日志文件就上傳或是日志文件達(dá)到一定大小再上傳,這就要根據(jù)實際情況來定啦。
當(dāng)我們應(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è)計有所幫助。
相關(guān)文章
Android?自定義開源庫?EasyView實現(xiàn)詳解
這篇文章主要為大家介紹了Android自定義開源庫EasyView實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04詳解Android:向服務(wù)器提供數(shù)據(jù)之get、post方式
本篇文章主要介紹了詳解Android:向服務(wù)器提供數(shù)據(jù)之get、post方式,具有一定的參考價值,有興趣的可以了解一下。2017-03-03Android開發(fā)快速實現(xiàn)底部導(dǎo)航欄示例
這篇文章主要為大家介紹了Android開發(fā)快速實現(xiàn)底部導(dǎo)航欄的示例代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-04-04Android對圖片Drawable實現(xiàn)變色示例代碼
這篇文章主要給大家介紹了關(guān)于Android對圖片Drawable實現(xiàn)變色的相關(guān)資料,文中通過示例代碼將實現(xiàn)的方法介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-08-08Android App中實現(xiàn)可以雙擊放大和縮小圖片功能的實例
這篇文章主要介紹了Android App中實現(xiàn)可以雙擊放大和縮小圖片功能的實例,文中的例子不能做到逐級放大但可以做到邊界控制和以觸摸點為中心進行放大,需要的朋友可以參考下2016-03-03