2016-03-08 76 views
1

我創建了一個類BaseActivity extends AppCompatActivity,我的Android應用中的所有Activites都從中繼承。在Android中記錄未處理的異常活動

在這個類中,我打算捕獲所有未處理的異常,所以我可以將它們寫入本地SQLite數據庫,以便以後檢查/發送到遠程服務器。

下面附上全班代碼:

public class BaseActivity extends AppCompatActivity { 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); 

    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 
     @Override 
     public void uncaughtException(Thread paramThread, Throwable paramThrowable) { 
      Log.e("Uncaught Exception", paramThrowable.getMessage()); 
      logError(paramThrowable); 
      defaultHandler.uncaughtException(paramThread, paramThrowable); 
     } 
    }); 
} 

private void logError(final Throwable paramThrowable){ 
    try { 
     ApplicationError error = new ApplicationError(); 

     String stackTrace = ""; 
     for (int i = 0; i < paramThrowable.getStackTrace().length; i++) { 
      stackTrace += paramThrowable.getStackTrace()[i].toString() + "\n"; 
     } 

     Throwable tmp = paramThrowable; 
     int j = 0; 
     while ((tmp = tmp.getCause()) != null && j < 5) { 
      j++; 
      stackTrace += "Coused by:\n"; 
      for (int i = 0; i < tmp.getStackTrace().length; i++) { 
       stackTrace += tmp.getStackTrace()[i].toString() + "\n"; 
      } 
     } 

     Log.e("Saving error...", ""); 

     String deviceInfo = ""; 
     deviceInfo += "OS version: " + System.getProperty("os.version") + "\n"; 
     deviceInfo += "API level: " + Build.VERSION.SDK_INT + "\n"; 
     deviceInfo += "Manufacturer: " + Build.MANUFACTURER + "\n"; 
     deviceInfo += "Device: " + Build.DEVICE + "\n"; 
     deviceInfo += "Model: " + Build.MODEL + "\n"; 
     deviceInfo += "Product: " + Build.PRODUCT + "\n"; 

     error.mDeviceInfo = deviceInfo; 
     error.mErrorMessage = paramThrowable.getMessage(); 
     error.mStackTrace = stackTrace; 

     error.save(); 

     Log.e("Saved error:", error.mErrorMessage + "\n" + error.mStackTrace); 
    }catch(Exception e){ 

    } 
} 

} 

對於澄清:ApplicationError只是它處理使用DBFlow保存到數據庫模型類。

問題

每次未處理的異常發生時(不要緊它是什麼)在活動二奇怪的事情發生了:

  1. logError()方法被調用一次以上,有時甚至8-10倍。看着日誌,我可以看到他們有幾乎相同的時間戳。
  2. 消息「XXX申請已停止」顯示在設備屏幕(這是好的),但關閉它後應用程序掛,我需要強制停止從應用程序設置屏幕。

燦任何人能幫助我嗎?還是有解決問題的更好的辦法?

在你的處理器
+1

你知道有框架,會爲你做這個吧? Crashlytics,Acra,Bugsense等 –

+0

執行任何這些支持在同步期間將錯誤發送到自定義服務器應用程序?我需要澄清一點,我需要將錯誤存儲在數據庫中以備以後同步,因爲即使脫機時,應用程序也會記錄錯誤以供稍後同步。 – jdabrowski

+0

所有這些都會緩存發生的錯誤,並在存在活動的網絡連接時發送它們。我相信,ACRA(也許其他人,我不知道)會支持發送到您自己的定製服務器。 –

回答

1

我設法最後用的AAG's answer幫助解決這個問題。

@AAG你是對的,每次調用任何活動中的onCreate()方法時都會添加異常處理程序。

@AAG但是你錯了沒有使用defaultHandler。我必須使用它,以便Android正確處理應用程序崩潰。

感謝您的幫助!

這是固定的代碼:

public class BaseActivity extends AppCompatActivity { 

    public static Context applicationContext = null; 
    public static Thread.UncaughtExceptionHandler defaultHandler = null; 
    public static Thread.UncaughtExceptionHandler exceptionHandler = null; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     if(defaultHandler == null){ 
      defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); 
     } 

     if(applicationContext == null){ 
      applicationContext = getApplicationContext(); 
     } 

     if(exceptionHandler == null){ 
      exceptionHandler = new Thread.UncaughtExceptionHandler() { 
       @Override 
       public void uncaughtException(Thread paramThread, Throwable paramThrowable) { 
        Log.e("Uncaught Exception", paramThrowable.getMessage()); 
        logError(paramThrowable); 
        defaultHandler.uncaughtException(paramThread, paramThrowable); 

       } 
      }; 

      Thread.setDefaultUncaughtExceptionHandler(exceptionHandler); 
     } 
    } 

    private static void logError(final Throwable paramThrowable){ 
     try { 
      ApplicationError error = new ApplicationError(); 

      String stackTrace = ""; 
      for (int i = 0; i < paramThrowable.getStackTrace().length; i++) { 
       stackTrace += paramThrowable.getStackTrace()[i].toString() + "\n"; 
      } 

      Log.e("Saving error...", ""); 

      Throwable tmp = paramThrowable; 
      int j = 0; 
      while ((tmp = tmp.getCause()) != null && j < 5) { 
       j++; 
       stackTrace += "Coused by:\n"; 
       for (int i = 0; i < tmp.getStackTrace().length; i++) { 
        stackTrace += tmp.getStackTrace()[i].toString() + "\n"; 
       } 
      } 

      String deviceInfo = ""; 
      deviceInfo += "OS version: " + System.getProperty("os.version") + "\n"; 
      deviceInfo += "API level: " + Build.VERSION.SDK_INT + "\n"; 
      deviceInfo += "Manufacturer: " + Build.MANUFACTURER + "\n"; 
      deviceInfo += "Device: " + Build.DEVICE + "\n"; 
      deviceInfo += "Model: " + Build.MODEL + "\n"; 
      deviceInfo += "Product: " + Build.PRODUCT + "\n"; 

      error.mDeviceInfo = deviceInfo; 
      error.mErrorMessage = paramThrowable.getMessage(); 
      error.mStackTrace = stackTrace; 

      error.save(); 

      Log.e("Saved error:", error.mErrorMessage + "\n" + error.mStackTrace); 
     }catch(Exception e){ 

     } 
    } 

} 
2

,您呼叫

defaultHandler.uncaughtException(paramThread, paramThrowable);

你不應該這樣做。每次的onCreate是調用(根據您的應用程序的使用情況,這可能很多) - 您正在創建一個調用舊處理程序的處理程序。所以第三次onCreate是調用,你將調用在第二次調用時創建的處理程序,然後調用在第一次調用時創建的處理程序。

刪除此之後,您的onCreate方法現在應該是:

protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 


    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 
     @Override 
     public void uncaughtException(Thread paramThread, Throwable paramThrowable) { 
      Log.e("Uncaught Exception", paramThrowable.getMessage()); 
      logError(paramThrowable); 
     } 
    }); 

}

+0

感謝您的答案!這部分解決了第一個問題。如果沒有這一行,默認處理程序不會被調用,所以AndroidOS不會顯示「應用程序已停止」消息,並且不會重新啓動應用程序。結果我們在問題2中。 – jdabrowski