2016-03-08 3 views
1

Я создал класс BaseActivity extends AppCompatActivity, из которого наследуются все мои Activites в приложении для Android.Регистрация необработанных исключений в Android Activity

В этом классе я собирался поймать все необработанные исключения, поэтому я могу записать их в локальную базу данных 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

Все они кэшируют ошибки, которые случаются offlie и отправляют их, когда есть активное сетевое подключение. 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);

вы не должны делать это. Everytime 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

Смежные вопросы