2016-06-27 19 views
6

umgehen Ich würde gerne Ihre Möglichkeiten, verschiedene Arten von Fehlern (wie HTTP-Ausnahmen, keine Internet-Verbindung Ausnahmen usw.) in Retrofit Rx onError ohne Verwendung von instanceof wie es ist zu behandeln hier vorgeschlagen: How to handle network errors in Retrofit 2 with RxJava oder hier: Handle errors in Retrofit 2 RXWie mit verschiedenen Arten von Fehlern in Retrofit Rx onError ohne hässliche instanceof

In Kotlin werde ich einfach einige Erweiterungsfunktionen für jede Art von Throwable tun, was auch immer ich will.

Aber ich bin gezwungen, Java in dem Projekt zu verwenden. Irgendwelche netten Vorschläge?

ist der Ansatz, eine Art von Fehler-Handler wie folgt zu erstellen:

public interface ErrorHandler { 
    void handleError(Exception e); 
    void handleError(HttpException e); 
    void handleError(NullPointerException npe); 

} 

gut? Ich weiß, es ist nicht, weil jedes Mal, wenn ich einen anderen spezifischen Fehler behandeln muss, ich gezwungen bin, Schnittstelle zu ändern, so ist es Verletzung von Open Close-Prinzip. Aber ich kann keine Lösung finden.

prost Wojtek

+0

das fällt immer in die 'handleError (Exception e)' Implementierung – mihail

+0

hmmm, ich schrieb Test dafür und es hat nicht versagt ... aber es ist irrelevant: P –

+0

Ich schrieb auch einen Test in Java 1.8 (u60) und es fällt immer in Exception-Methode – mihail

Antwort

1

Der Compiler legt fest, welche Methode zu nennen, anstatt die VM. Die von Ihnen beschriebene Klasse löst das Problem also nur, wenn Sie instanceof zuerst überprüfen und den Parameter in den richtigen Typ umwandeln. Sonst wirst du jedes Mal handleError (Exception e) bekommen.

Aber ich wollte nicht aus diesem Grund eine Antwort erstellen, sondern argumentieren, dass es in vielen Fällen tatsächlich vorzuziehen ist, nur einen Fehlerbehandler zu haben, keine Haftung. Oft in Java enden wir in schreckliche Situationen wie diese auf:

catch (NoSuchAlgorithmException e) { 
     throw new IllegalStateException("No such algorithm: RSA?", e); 
    } 
    catch (NoSuchProviderException e) { 
     throw new IllegalStateException("No such provider: " + ANDROID_KEYSTORE_ID, e); 
    } 
    catch (InvalidAlgorithmParameterException e) { 
     throw new IllegalStateException("Bug setting up encryption key for user credentials: ", e); 
    } 
    catch (KeyStoreException e) { 
     throw new IllegalStateException("Bug setting up encryption key for user credentials: ", e); 
    } 
    catch (IOException e) { 
     Log.w(TAG, "Exception setting up keystore for user creds. They won't be stored.", e); 
    } 
    catch (CertificateException e) { 
     Log.w(TAG, "Exception setting up keystore for user creds. They won't be stored.", e); 
    } 

mit nur einem Fehler-Handler gibt uns die Möglichkeit, zusammen viele Arten von Ausnahmen einen Topf zu werfen. Sie können in diesem Code sehen, dass es Ausnahmen gibt, die niemals ausgelöst werden sollten, Ausnahmen, die wirklich nur das Ergebnis eines Fehlers im Code sein können, und legitime Ausnahmezustände, die wir behandeln müssen. Ich finde diese chaotisch, und würde lieber sagen:

if (e instanceof NoSuchAlgorithmException || e instanceof NoSuchProviderException) { 
    Log.wtf(TAG, "What the heck is this?", e); 
    throw new IllegalStateException("This is some kind of weird bug", e); 
} 
else if (e instanceof IOException || e instanceof CertificateException) { 
    // This can happen sometimes, track event in analytics and perhaps 
    // try some alternative means of credential storage. 
} 
else { 
    // At least here the app won't crash if some unexpected exception occurs, 
    // since we're trapping everything. 
} 

Ich glaube nicht, dass es so eine schlechte Sache der Lage sein, unerwartete Ausfälle zusammen einen Topf zu werfen und sie in einer benutzerfreundlichen Art und Weise handhaben als die App abstürzt. Auch wenn es nur ein Bug ist, ist es besser, ihn hinter den Kulissen in Ihrem Analytics-Framework zu verfolgen, als den Nutzer aus der App zu bombardieren. So viele Abstürze in Android-Apps sind tatsächlich vollständig wiederherstellbar, aber wir gehen nicht herum und fangen Throwable in jeder try/catch-Anweisung ein, weil es viel zusätzlichen Code ist.

1

Die richtige OOP Weise if s oder catch es ist Polymorphismus gekettet zu vermeiden. Sie können mehrere benutzerdefinierte Ausnahmeklassen definieren, die eine allgemeine Schnittstelle anzeigen, die für die Verarbeitung durch einen einzelnen Handler ausreicht.

Angenommen, Sie müssen Fehler in zwei Gruppen aufteilen: wiederherstellbar und nicht wiederherstellbar. Dann muss Ihre Basisausnahmeklasse (oder Schnittstelle) die abstrakte Methode isRecoverable() haben, die Sie in jeder Unterklasse überschreiben. Dann wird es nur einen if in Ihrem Handler geben: if (e.isRecoverable()) { ... } else { ... }.

Der Nachteil ist, dass Sie alle Standard-Ausnahmen in Ihre eigenen an den Stellen, wo sie geworfen werden müssen (Sie müssen sie fangen).

Die richtige Wahl hängt jedoch stark von Ihrer Aufgabe ab.