溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android編程實現(xiàn)項目中異常捕獲及對應(yīng)Log日志文件保存功能

發(fā)布時間:2020-08-28 21:08:43 來源:腳本之家 閱讀:200 作者:遲做總比不做強 欄目:移動開發(fā)

本文實例講述了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è)計有所幫助。

向AI問一下細節(jié)

免責聲明:本站發(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)容。

AI