2014-02-18 4 views
1

У меня есть обработчик (Thread), на котором я отправляю Runnables. В случае, если Runnable по ошибке выбрасывает исключение RuntimeException, происходит сбой всего процесса приложения. По умолчанию это звучит разумно, но я бы хотел поймать такие исключения во время выполнения, зарегистрировать ошибку и продолжить работу. Однако я затрудняюсь с этой работой. Я думал, что из следующих вариантов:Избегайте сбоя резьбы обработчика в случае исключения времени выполнения?

  1. Подкласс Looper и переопределить loop(), который содержит код, вызывающий run() метод отправленного Runnables. Это не сработало, так как Looper является окончательным.
  2. Подкласс HandlerThread и переопределить метод прогона, который вызывает Looper.loop(). В случае исключения времени выполнения вызовите снова super.run() и так далее. Это не сработало, поскольку «только один Looper может быть создан для потока».
  3. В каждый класс runnable включаются исключения try-catch для Runtime. Это будет работать, но довольно раздражает, так как у меня довольно много разных классов Runnable. Кроме того, не будет защищать поток обработчика, если запущенная по ошибке забывает включить try-catch.

В идеальном мире, Looper бы метод члена под названием registerExceptionHandler(ExceptionHandler) и ExceptionHandler затем вызываться в случае исключения.

Кто-нибудь получил лучшее предложение?

+0

поставил код работоспособной в примерочных поймать блока и поймать исключение. Таким образом, runnable не будет выбрасывать исключения. Вы можете управлять исключением в блоке catch в соответствии с вашими потребностями. – guptakvgaurav

+0

Правильно, я думаю, что это то, что я называю опцией 3, и я вижу это как обход. Проблема в том, что у меня есть несколько классов Runnable, и я хотел бы избежать добавления такого кода к каждому из них. – TommyTh

ответ

2

попробовать этот пользовательский обработчик:

class H extends Handler { 
    public H(Looper looper) { 
     super(looper); 
    } 

    @Override 
    public void dispatchMessage(Message msg) { 
     // catch any Exception 
     try { 
      super.dispatchMessage(msg); 
     } catch (Exception e) { 
      Log.d(TAG, "dispatchMessage " + e.getMessage()); 
     } 
    } 
} 

тестирования кода:

HandlerThread ht = new HandlerThread("hthread"); 
ht.start(); 
Handler h = new H(ht.getLooper()); 

Runnable r = new Runnable() { 
    @Override 
    public void run() { 
     throw new RuntimeException("testing exception"); 
    } 
}; 
h.post(r); 
h.post(r); 
+0

Да, именно так вы настраиваете и запускаете HandlerThread. Если вы делаете что-то вроде 'ht.post (new RuntimeGeneratingRunnable)', процесс приложения будет аварийно завершен. Любая идея, как этого избежать? – TommyTh

+0

Не используйте Runnables, используйте send * Message * и Handler.Callback – pskink

+0

Правильно, это сработает. Мне пришлось бы превращаться в использование сообщений вместо Runnables, поэтому я бы предпочел добавить try-catch для всех Runnables ... Если ничего лучше не появится. – TommyTh

0

В идеальном мире DefaultExceptionHandler работает как шарм для меня во всем приложении. Там, где он вызывает необработанное исключение, он запускается.

Библиотека под названием Android-Remote-StackTrace. Вам просто нужно зарегистрировать трансляцию этого класса DefaultHandlerException в вашем классе Application.

Отрывок:

public class Portfolio extends Application { 
static Portfolio portfolio; 
public void onCreate() { 
    super.onCreate(); 
    portfolio = this; 
    ExceptionHandler.register(portfolio);// registering for unhandled Exceptions 
    } 
} 

Вы можете сделать различные задачи с ними, такие как загрузка журнала трассировки стека на сервер или отправки почты на крахе приложения в отчет об ошибке с вашей необработанного Stack Trace.

+0

Не совсем то, что я просил, но, безусловно, кажется полезным. Я сразу подумал, что слишком поздно «восстанавливать» поток обработчика, но я не уверен. Я исследую и дам вам знать. Спасибо, что ответили! – TommyTh

+0

Я посмотрел на него. Я не знал, что существует DefaultExceptionHandler; безусловно, интересный и заслуживающий внимания. В этом конкретном случае это означало бы, что любые ожидающие выполнения в очереди будут потеряны, и поток обработчика должен быть перезапущен и т. Д. Так что это не очень хорошо подходит, к сожалению :-(. – TommyTh

0

Самый простой способ, как представляется, вывести из Runnable:

public abstract class RunnableBase implements Runnable 
{ 
    public final void run() 
    { 
     try { 
      runInternal(); 
     } 
     catch(Exception e) { 
      // handle the exception 
     } 
    } 

    // to be implemented by concrete subclasses 
    protected abstract void runInternal(); 
} 
Смежные вопросы