Verständnisfrage Asynctask

  • Hallo


    Ich möchte mir eine App erstellen in der ich einen TCP/IP Client integriere.


    Da ich ja die Netzwerksache nicht im Main Thread machen kann habe ich mir die Sache mit Asynctask angeschaut.


    Leider habe ich da große Probleme zu verstehen wie die ganze Sache gehandelt wird.


    Frage1:


    Was passiert wenn ich in der Methode doInBackground(...) eine Klasse instanziere
    z.B. ipcon = new IPConnection();


    Wenn kein weiterer Code in doInBackground steht springt er ja direkt in onPostExecute(...) richtig?


    Was aber passiert nun mit dieser Instanz "ipcon" ? Läuft die im Main Thread, oder läuft die in einem neuen Thread oder ist sie ganz weg weil der AsyncTask bereits abgeschlossen wurde?
    Kann ich auf die Methoden dieser Instanz noch zugreifen?


    Frage2:


    Ich schreibe in doInBackground(...) folgendes
    z.B.


    clientSocket = new Socket("192.168.1.1", 2002);
    in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));


    Es werden ja dann auch nur die Socketverbindung und die 2 Buffer erstellt. Anschließend wird gleich in onPostExecute(...) richtig?


    Was passiert dann mit der Verbindung? Läuft die in einem anderen Thread, oder ist sie weg weil der AsyncTask bereits abgearbeitet wurde?
    Kann ich noch auf die Buffer zugreifen?


    Ich weiß die Fragen sind total blöd, aber ich finde irgendwie keine Erklärung/Antwort weil es wohl zu trivial ist.


    Danke schon mal


    Gruß snipor

  • Hi Snipor,


    deine Fragen 1 & 2 laufen eignetlich aufs selbe hin:
    Wenn du deine ipcon / socket etc variablen nur im "doinbackground" hälts und keine refernez in deiner klasse die den async task aufruft hälst, oder sonst wo, dann kannst du ausserhalb des async task sowieso nicht mehr darauf zugreifen, der garbage collector wird die nach belieben verwerfen.
    Wenn du die variablen aber in deiner klasse definiert hast, und nicht nur im "doinbackground", dann sind sie auch nacher noch vorhanden. die methoden werden aber immer in dem thread ausgführt, von dem du sie aufrufst. instanziert du deine tcp/ip sachen also im "doinbackground" gibts keinen fehler, führst du dann aber im mainthread eine funktion darauf aus, wirds wohl eine "networkonmainthread" exception geben.
    Gut, dass nützt dir nichts :)


    Ich denke eher es ist eine konzeptionelle frage. Was willst du genau anstellen?
    Willst du etwas einmalig tun, zB ein Bild herunterladen oder eine http get / post anwort erhalten? Dann ist der AsyncTask okay, du instanziert alle network sachen im DoInBackground, führst deine anfragen aus, schliesst alle connections wieder sauber.
    Willst du allerdings etwas machen das "länger" hält, also die verbindung aufrecht erhält und auf einen aktion vom server wartet um antwort zu geben, oder vielleicht alle 10sekunden etwas schickt? Dann würde ich eine separate Klasse erstellen welche einen eigenen Thread erstellet der solange läuft wie deine App läuft (oder du halt die Verbindung brauchst)

  • Danke für deine Antwort.


    Also ich brauche eine dauerhafte Verbindung.


    Ich bräuchte also wenn ich einen AsyncTask verwenden möchte eine dauerhafte Schleife darin, die solange läuft wie die App aktiv sein soll, oder?


    Wie sollte ich es richtig machen?


    Einen neuen Thread mit runnable? Wie greife ich dann vom GUI Thread auf den Socket bzw. die Buffer zu?


    Danke

  • Ja, bei dauerhafter Verbindung ist der AsyncTask aber nicht zu empfehlen!


    Genau, separate Klasse mit einem Endlos Loop der deine Kommunikation macht, dazu ein paar Callbacks für deine Acitvity das neue Daten parat sind.
    Dort dann einfach darauf schauen, dass wenn du UI Elemente aktualisiert, dies unbedignt auf dem MainThread tun musst.
    Da mir gerade ein bisschen langweilig war habe ich dir ein kleines Demo Project gemacht.
    Das liest alle 5 Sekunden die aktuelle Uhrzeit von einer Webseite und senden sie an deine MainActivity, dort wird auf dem UI Thread die View aktualisiert.
    Der Code ist extra simpel gehalten, keine saubere Exception auswertung, das warten ist hässlich gelöst, der Client sollte noch disposed werden etc, aber je weniger code desto einfacher zu verstehen. Einfach fragen wenn etwas nicht klar ist.


    Zip File ist hier:
    http://nibdev.com/NetTimeDemo.zip

  • Danke für das Beispiel das hat mir schonmal geholfen.


    Aber dennoch möchte ich nochmal auf meine Ausgangsfrage zurückkommen.


    Ich würde sehr gerne wissen was genau mit einer in einem Asynctask erstellten Socketverbindung oder Instanz einer Klasse passiert nachdem der Asynctask durchgelaufen ist.


    Wird das vom Garbage Collector dann einfach aufgeräumt, oder kann ich das noch nutzen?


    Ich habe jetzt die ganze Woche danach gesucht aber eine Erklärung hab ich niergends gefunden.


    Wäre sehr dankbar für eine Antwort oder Link.


    Danke

  • Wird das vom Garbage Collector dann einfach aufgeräumt, oder kann ich das noch nutzen?


    Diese Frage ist etwas schwierig zu beantworten.
    Die Kurzfassung ist: du sollst dich selbst darum kümmern, deine Dinge (geöffnete Streams, Sockets, Connections, Files etc.pp.) selbst wieder frei zu geben.
    Im Falle des Async Task hast du den Vorteil, dass nach dessen Beendigung sämtliche Instanzvariablen ihr Signal zur Freigabe erhalten. Der Garbage Collector räumt dann also alles auf. Leider kann es einige Dinge geben, die beim Aufräumen nicht durchgeführt werden. Das Schließen von Streams einer Socketverbindung zum Beispiel. Hängt also ganz von der Implementierung des Objektes ab.


    Zurück zum Thema: solltest du die Verbindung oder Instanz ausschließlich in diesem AsyncTask deklariert und zugewiesen haben, dann kommst du nach Beendigung des Tasks nicht mehr ran. Dir fehlt einfach die Referenz zu dem Objekt. Hast du deinem AsyncTask hingegen das Objekt als Referenz mitgegeben, ist es nach Beendigung des Tasks für dich noch immer verfügbar.

    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!«

  • Könntest du mir evtl. ein einfaches Beispiel geben wie ich eine solche Referenz in die MainActivity machen müsste?


    Würde es reichen wenn ich z.B. schreiben würde R= new Insatz() und dann dass R ins Return von doInBackground schreibe?
    Oder wie macht man das am besten?



    Vielen Dank

  • Also zunächst einmal ist das Java, kein Assembler. Man darf, kann und soll seine Variablen sinnvoll ausschreiben. ;)


    Weiterhin finde ich es nicht wartbar, wenn irgendwelche Klassen auf irgendwelche Member irgendwelcher anderen Klassen zugreifen.


    Die Main würde ich dann so gestalten:


    Und den Task selbst einfach ein wenig erweitern.

    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!«

  • Hallo,


    danke für das Beispiel.


    Aber komme ich dann nicht wieder in das Problem mit der NetworkinMainThreadExpetion? Es soll ja scheinbar alles was mit Netzwerk zu tun hat in einem extre Thread gemacht werden


    So ganz komme ich noch hinter das Multithreading, und in der Tat habe ich vorher fast nur auf Mikrocontrollern auch in Assembler programmiert, alles sequentiell.


    Ich weiß auch leider nicht wie ich da an die ganze Sache am besten ran gehen soll.


    Ich hatte mir überlegt es generell evtl. so zu machen.


    Ich habe einen Main Thread der für das UI usw zuständig ist und bei Bedarf auch Nachrichten an über die Buffer schicken kann.


    Zunächst starte ich dann bei Bedarf aus dem UI Thread bei Druck auf einen Button einen neuen Thread, in diesem öffne ich nur den Socket.


    Sobald dann der Socket gebunden ist (isBound() ) soll dann ein weiterer Thread aus dem Main Thread aus gestartet werden. In diesem werden dann die Buffer erstellt. Dieser Thread muss dann wohl dauerhaft laufen (Endlosschleife?) und auf Nachrichten vom Server warten.


    Vom Main Thread aus muss ich ja auch auf die Buffer bzw den Socket zugreifen können.



    Was denkst du darüber? Sollte man das so machen, oder anders?



    Eines der Hauptprobleme scheint wohl jetzt zu sein dass ich in den MainThread eine Referenz auf den Socket bringen muss, da ja der Thread für den Socket schnell durchgelaufen ist. Und ansonstne räumt der Garbage Collector ja den Socket auf.



    Wäre das hier richtig um eine Referenz in den MainThread zu haben, so dass die Objekte aus dem AsyncTask nicht vom Garbage Collector gelöscht werden?



    Danke schonmal


    Gruß

  • Solange du nur ein Socket Objekt erstellst (oder ein Netzwerkobjekt im Allgemeinen) dürfte soweit ich weiß keine Exception gefeuert werden.
    Erst wenn du die Verbindung startest, solltest du dich außerhalb des UI Threads befinden.


    Zu deinem theoretischen Ansatz:
    Neuen Task starten und da die Socketverbindung erstellen klingt gut.


    Doch warum willst du die Buffererstellung in einem weiteren Task ausführen?
    Da jeder Task wohl sequentiell abgearbeitet wird bringt dir das relativ wenig. Wenn du auf parallele Ausführung bestehst, bringt dir das ebenfalls wenig, da jeder Thread seinen eigenen Speicherbereich zugeteilt bekommt. Hin und her referenzieren wird da also schwierig.


    Wofür du jetzt die Referenz auf die Buffer brauchst erschließt sich mir nicht. Doch mit meinem Beispiel hast du sie ja.
    (Natürlich sind die irgendwann fertig und könnten geschlossen werden. Ein read auf einen solchen Buffer zu werfen würde dann schwierig und vermutlich in einer Exception enden.)


    Aber so ganz konkret habe ich keine Idee was genau du eigentlich bezweckst.
    Eventuell wäre es hilfreich, du würdest dein Vorhaben konkreter beschreiben anstatt deines Lösungsansatzes.
    Dann kann man dir nämlich nicht nur sagen, ob dein Lösungsansatz der richtige ist, man könnte dir auch sagen, wie du ihn optimiert bekommst.


    Wenn du das verständlicherweise nicht in öffentlichen Foren machen möchtest, dann geht das sicher auch per PN. ;)

    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!«

  • Ich habe dir mal eine PN geschickt.


    Edit:
    Hier mal die Beschreibung


    Meine App hat folgenden Zweck.


    Ich habe hier ein Carambola Wlan Modul, dieses fungiert als WLAN
    Access Point. Das Android Gerät kann sich dann damit verbinden.


    Außerdem dient das Carambola Modul auch als TCP/IP Server,
    es stellt mir einen TCP Socket zur Verfügung.


    Das Android Gerät soll dann eine Socketverbindung zu dem
    Modul aufbauen.


    Den Datenstrom über den Socket leitet das Carambola Modul an
    einen Mikrocontroller via serieller Schnittstelle weiter.


    Die App soll nun also eine Socketverbindung aufbauen, und
    diese dauerhaft offen halten solange die App im Vordergrund ist.


    Über den Socket sollen dann dauerhaft sowohl Befehle von der
    App an das Carambola, als auch vom Carambola zur App geschickt werden können.



    In meinem angefangen Beispiel soll beim Druck auf eine
    Taste dann z.B. der Befehl „EIN“ an das Carambola gesendet werden.


    http://geo-delta.de/sonstiges/AVR-IO-Test.rar

  • In dem Fall sollte sich ein Service in einem eigenen Thread um die Verbindung zum WLAN Modul kümmern.
    Deine App(s) kommunizier(t/en) dann über Broadcast Messages mit dem Service und vice verda.

    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!«

Jetzt mitmachen!

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