Java Plugin-Klassen richtige Implementierung

  • Hallo,
    ich wollte eine App schreiben, die mit Plugins erweiterbar ist, konkret geht es in der App darum, dass man SMS von einem Web-Sms-Provider (bsp. smstrade.de) sendet und nicht über die Mobilfunkprovider.
    Um nun die App einfach mit weiteren Web-SMS-Providern erweiterbar zu machen, wollte ich eine Art Plugins schreiben (die Plugins müssen nicht dynamisch in der App hinzugefügt werden können, sondern einfach zur Compilezeit zur Verfügung stehen)


    Über ein Einstellungsmenü kann man den Provider aus der Liste wählen.
    Für jeden Provider muss es aber außerdem noch ein eigenes Provider-Einstellungsmenü geben.


    Nun habe ich das ganze So gelöst, dass ich im Einstellungsmenü aus einem StringArray die Provider wählen kann und anschließend wird mit String-Vergleichen überprüft, ob es einen solchen Provider gibt. Sollte es diesen geben, wird eine neue Instanz (mit dem Sender, empfänger und dem Text der Nachricht erzeugt)



    Nun brauche ich aber auch noch die Providerabhängige Settings-Klasse und zwar wirklich die Klasse, keine Instanz. Diese Settings-Klasse ist eine Inner-Class der ProviderKlasse. Aber hier muss ich wieder den gleichen Code schreiben, denn ich muss ja dann die Sender-Settings-Klasse über einen Intend starten:


    Nun habe ich aber in beiden Fällen fast den Gleichen Code.
    Wie kann ich das ganze eleganter lösen, dass ich den Code mit den If-Abfragen, die die Senderklasse auswählen nur noch einmal habe? (Ich brauche einmal die Instanz der Basisklasse, das andere mal die Klasse der Kindklasse.)


    falls etwas unklar ist, ich habe dieseApp auf Github veröffentlicht, hier kann man sich die Konkreten files ansehen.
    https://github.com/mwuehrer/sms_sender


    Konkret bezieht sich meine Frage somit auf die Dateien
    https://github.com/mwuehrer/sm…_sender/MainActivity.java
    https://github.com/mwuehrer/sm…nder/plugin/SmsTrade.java


    ich weiß das ist etwas kompliziert geschrieben, aber ich weiß leider nicht, wie ich es anders formulieren soll.

  • Ich glaube, für so etwas solltest du das Factory Pattern nehmen. Diese Aufgabenstellung ist wie geschaffen für dieses Pattern. :)


    Ein ganz schneller Workaround wäre übrigens, die Methode so zu schreiben:



    Der Oberbegriff nennt sich im Fachjargon 'Refactoring' und diese Aktion 'Method Extraction'.


    Du solltest aber wirklich versuchen, das Factory Entwurfsmuster anzuwenden.
    Das macht das Ganze wesentlich einfacher zu erweitern und auch übersichtlicher.


    Wenn du Fragen diesbezüglich hast, dann frag. :)

    Je mehr Käse, desto mehr Löcher.
    Je mehr Löcher, desto weniger Käse.
    Daraus folgt: je mehr Käse, desto weniger Käse.


    »Dies ist ein Forum. Schreibt Eure Fragen in das Forum, nicht per PN!«

  • Danke Lucas für die schnelle Antwort, stimmt, ja dein workaround ist natürlich auch möglich, nur hab ich das ganze einfach nur schnell copy&paste hingeschrieben, weil ich sowieso gehofft hab, dass es das ganze als schönere lösung auch gibt...
    aber danke trotzdem dafür. :)


    ich hab schon mal von dem factory-pattern gehört, aber ich bin mir nicht sicher, wie ich die richtig implementieren soll:
    ich sag einfach mal, was ich weiß:
    es gibt eine factory für jedes plugin (also für jeden sender), diese spezielle sender-factory implementiert ein generisches sender-factory interface.


    die if-abfrage mit den strings instanziert die spezielle factory je nach string,
    anschließend kann ich mit dieser factory-instanz dann eine methode getSettingsClass und getSenderClass implementieren.


    ist das so richtig?


    nur muss ich dann die factory an der stelle, an der ich die settings anzeige und an der stelle, an der ich die nachricht sende instanzieren? oder wäre es besser, wenn ich es als klassenmember in der main-activity abspeichere

  • So in etwa, ja.
    Ist natürlich etwas komplexer. +seufz+


    Als Klassenmember in der MainActivity nützt dir das Ganze vermutlich eher wenig, da du ggf. noch von der SettingsActivity darauf zugreifen musst.
    Allerdings bekommst du ja immer eine neue Instanz zurück, was später durchaus zu Probleme führen kann, wenn du auf jeder Activity die Factory auspackst.


    Ich muss darüber noch mal in Ruhe nachdenken. :)

    Je mehr Käse, desto mehr Löcher.
    Je mehr Löcher, desto weniger Käse.
    Daraus folgt: je mehr Käse, desto weniger Käse.


    »Dies ist ein Forum. Schreibt Eure Fragen in das Forum, nicht per PN!«

  • Najo da es nicht praktikabel ist, die Objekt-Listen in den einzelnen Activitys zu halten, würde ich eine Handler-Klasse erstellen.



    Sowas die Richtung. Man hat seine Liste nur 1 mal, sie bleibt bestehen, wenn man die Activity wechselt und kann bequem drauf zugreifen. "Settings" wär hier dann wohl ein Interface oder eine abstrakte Klasse. Pro spezielle Settings eine Unterklasse. Die Liste kann sich dann an entsprechender Stelle geholt werden und dank Polymorphismus bequem durchrödelt werden oder was auch immer man im Schilde führt ;)



    Gruß,
    Matze

  • Danke für den Hinweis.
    Ich habe das ganze jetzt so implementiert:



    Allerdings muss ich mich somit auch darum selbst kümmern, wenn sich jetzt der gewählte sender ändert.
    Dazu habe ich dann bei android deveolpers was gefunden:
    https://developer.android.com/…i/settings.html#Listening


    hier wird behauptet, dass ich einen onSharedPreferenceChanged-handler machen kann, das funktioniert allerdings nicht.
    die hier dargestellten Log-Einträge (DEBUG1, DEBUG2 und DEBUG3) scheinen nämlich nicht in den Logs auf, das bedeutet wohl, dass der code hier nie aufgerufen wird.


    Hier noch die gekürzte version der MainActivity, wo die SettingsActivity aufgerufen wird.
    (Hier wird der DEBUG-Eintrag DEBUG_MAIN ausgeführt)


    Meine Frage somit, was mache ich beim Aufruf falsch, irgendwie glaube ich werden hier die Methoden überschrieben.

  • Auf den ersten Blick sieht der Aufruf korrekt aus. Allerdings finde ich den Code nicht, in dem du die geänderten Settings speicherst.


    Hast du eventuell eine Einstellung in deiner Logausgabe, dass Warnings nicht mit ausgegeben werden? (Hab ich bei mir, weil mir die [gefühlt] 100.000.000.000.000 Warnungen auf den Senkel gehen)


    Debugging mit Logausgaben ist übrigens eher ungeil, schmeiß lieber den Debugger an, setze Breakpoints und schau mal, wo du dann landest.

    Je mehr Käse, desto mehr Löcher.
    Je mehr Löcher, desto weniger Käse.
    Daraus folgt: je mehr Käse, desto weniger Käse.


    »Dies ist ein Forum. Schreibt Eure Fragen in das Forum, nicht per PN!«

  • Dankeschön matthias.
    ich hab die Seite https://developer.android.com/…i/settings.html#Listening mal wieder nicht ordentlich gelesen.


    Du hast natürlich recht, ich muss das Event erst registrieren. (Was ja eig. eh logisch ist, denn wie sollte man sonst auf das Event reagieren?)
    Ich habs nun geändert und nun funktionierts:



    Für alle, die den gesamten Code (das gesamte Projekt) noch brauchen, hab ich die korrigierte Version auf Github hochgeladen:
    https://github.com/mwuehrer/sms_sender

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!