Sich ändernder Status aus AsyncTask doInBackground abfragen/verwenden

  • Antworten:16
  • OffenNicht stickyBentwortet
  • Forum-Beiträge: 11

01.02.2016, 16:53:02 via Website

Hallo erstmal,
hier mein Problem:
ich will eine App schreiben die im Hintergrund die Verbindung überwacht (mit Ping's) und ggf auf Änderungen reagiert.
Ich starte also einen AsyncTask der alle 3sec die angegebene IP anpingt und bereite den Response dann für mich passend auf.
Nur wie schaffe ich es jetzt diese Information in meiner Activity abzufragen?
Also das muss ja dauernd ausgewertet werden.
Als bsp. Ping läuft im Hintergrund und liefert mir aufbereitet immer true oder false (Verbindung steht/abgebrochen) nun will ich in meiner Activity ein Image oder so einblenden oder ein neues Layot aufmachen (das muss ich mir noch genau überlegen) wenn die Verbindung abbricht, dieses soll sich aber wieder ändern/verschwinden wenn die Verbindung wieder steht.
Kann mir diesbezüglich jemand weiterhelfen... stehe echt etwas aufm Schlauch :D

im voraus besten Dank für eure Hilfe

gruß
Benjamin

Antworten
  • Forum-Beiträge: 2.243

02.02.2016, 09:34:30 via Website

Du übergibst einen Listener an den AsyncTask, wenn er gestartet wird (bzw. nochmal, wenn die Activity z.B. auf Grund von Rotation neu gestartet wird). Dann verwendest Du die publishProgress Methode, um den "Fortschritt" alle 3 Sekunden aus doInBackground an den Listener weiterzuleiten.

http://developer.android.com/reference/android/os/AsyncTask.html

Antworten
  • Forum-Beiträge: 11

02.02.2016, 18:12:57 via Website

danke für deine Antwort aber leider werde ich da nicht ganz schlau draus (bin blutiger Anfänger) versuche seit Weihnachten mir die Sache ansatzweise beizubringen :D
Du hast mir da nicht zufällig ein Beispiel dazu?

Antworten
  • Forum-Beiträge: 11

03.02.2016, 17:54:28 via Website

OK ich weiß jetzt glaube wo mein Fehler liegt bzw lag.
Ich hatte in meinem Projekt eine neue Java Klasse angelegt für den AsyncTask und diese mit einem Konstruktor aufgerufen und mit execute() das doInBackgraind gestartet. Jetzt habe ich alles was in der Klasse Stand einfach mal in die Activity kopiert und da als Klasse aufgemacht jetzt geht es da ich von da aus ja auf meine View´s zugreifen kann.
Aber geht das auch irgendwie so wie ich es am anfach hatte (also in ner separaten Klasse)?
Wenn ja wie muss ich das ganze dann in meiner Activity aufrufen bzw wie bekomme ich da Zugang zu den View Elementen und/oder Layouts?

Hoffe du kannst mit diesbezüglich auch noch weiterhelfen
falls du mal meinen Code brauchst zum dir die Sache anschauen sags mir einfach dann schick ich dir die entsprechenden Abschnitte per PN oder Mail

gruß
Benjamin

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.177

03.02.2016, 17:58:18 via App

Im AsyncTask bekommst du keinen Zugiff auf Views das muss der MainThread behandeln.
Du kannst auf den AsyncTask warten und per Callback in den MainThread zurück gehen und dort dann deine Views ändern.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
  • Forum-Beiträge: 2.243

03.02.2016, 21:37:17 via Website

Pascal P.

Im AsyncTask bekommst du keinen Zugiff auf Views das muss der MainThread behandeln.
Du kannst auf den AsyncTask warten und per Callback in den MainThread zurück gehen und dort dann deine Views ändern.

Das ist etwas mißverständlich ausgedrückt :)

Man hat nur in der doInBackground Methode keinen Zugriff auf UI-Objekte. In onPreExecute, onPostExecute, onProgressUpdate schon, denn die laufen im UI-Thread.

Hier ein Beispiel, wie man einen AsyncTask mit einem Listener verbindet:
http://stackoverflow.com/a/9963705

— geändert am 03.02.2016, 21:37:43

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.177

03.02.2016, 22:06:12 via App

Da hast du allerdings recht ;)
Jedoch mag ich keine Halben Sachen, finde es per Callback sauber getrennt am Besten.

— geändert am 03.02.2016, 22:06:39

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
  • Forum-Beiträge: 11

04.02.2016, 16:49:31 via Website

OK ich blick´s immer noch nicht :'(
hier jetzt mal ein gekürzter Auszug aus meinem Programm vielleicht wird´s euch und mir dann etwas klarer
so hatte ich mir das gedacht.....
Als erstes meine Activity:

public class StartActivity extends AppCompatActivity {

//Deklarieren der View Elemente von der StartActivity
Button ......

//Erzeugen eines neuen Objektes der Klasse "Ping"
Ping ping;

//Variablendeklaration
private String IP_adresse = "";
.........


//onCreate wird bei Appstart automatisch ausgeführt
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_start);   //"activity_start" als aktuelles Layout festlegen

    //Initialisieren der View Elemente über ihre ID
    btn_connect = ..........

}

//-------------------------Connect Button onClick-----------------------------------------------------------
public void connect(View v) {

     //TODO: IP überprüfen und in Variable"IP_adresse" übernehmen

     startePing();   
}
//Starten des AsynkTasks

private void startePing() {
    ping = new Ping(IP_adresse);
    ping.setStatus(true);
    ping.execute();
}
}//ende Activity

hier meine Java Klass "Ping" mit dem AsynkTask (neue Klasse/neues Fenster)

public class Ping extends AsyncTask<String ,Boolean ,String>{

private String IP_adresse;      //Übergebene IP Adresse aus StartActivity (Pingziel)
private boolean status;             //Variable zum starten/stoppen des Ping's
private boolean teststatus;

//-----------------Konstruktor----------------------------------------------------------------------

public Ping(String IP_adresse) {
    this.IP_adresse = IP_adresse;
}

//-------------------Setter und Getter--------------------------------------------------------------

public boolean isStatus() {
    return status;
}

public void setStatus(boolean status) {
    this.status = status;
}
//--------------------------------------------------------------------------------------------------

@Override
protected String doInBackground(String... params) {
    while(status) {

        .....Ping ausführen

        .....Ping auswerten (gibt am ende true oder false aus in "teststatus")

        publishProgress(teststatus);
    }
    return null;
}



@Override
protected void onProgressUpdate(Boolean... values) {

       //Was hier rein muss , bzw wie es ab hier weiter geht ist die frage
}

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);

}
}//Ende Ping klasse

so war in etwa mein Gedankengang und bis zu dem Punkt funktioniert auch alles nur wie bekomme ich nun meinen "teststatus" in die Activity und frage den da daueraft ab, bzw wie funktioniert es das ich in der Activity auf die Veränderung vom "teststatus" reagieren kann?
also quasi if(teststatus_changed) --> zeige anderes Layout .... oder tue sonst irgendwas
die onPostExecute geht ja nur wenn die doInBackground fertig ist als in den return läuft (wenn ich das richtig verstanden hab).
In meinem Fall geschieht das eigentlich nur wenn ich die App beende oder manuell eingreife (im normalen Betrieb soll das wenn einmal gestartet immer laufen)
Für änderungs-/verbesserungsvorschläge bin ich jederzeit offen :D

Antworten
  • Forum-Beiträge: 2.243

04.02.2016, 21:44:38 via Website

1)

public interface MyCoolListener {
    void onPingResult(boolean success);
}

2)

MainActivity implements MyCoolListener {
...
@Override
void onPingResult(boolean success) {
    // do stuff
}

3)

@Override
protected void onProgressUpdate(Boolean... values) {
      mListener.onPingResult(...)
}

Dabei ist mListener eine Instanz deiner Activity (die ja das Interface implementiert), die du an den AsyncTask übergibst.

Antworten
  • Forum-Beiträge: 11

05.02.2016, 12:55:42 via Website

OK
Wo muss ich denn schritt 1 machen?

schritt 2 is ja in meiner Activity und "//do stuff" ist in meinem Fall ja dann das Layout wechseln oder sonstwas über Views anzeigen/ändern

und bei schritt 3 rufe ich die Methode aus schritt 2 auf

wenn ich das jetzt bis hierhin soweit richtig Interpretiert habe.

Sry wenn ich mich ein wenig doof anstelle aber das ist für mich komplettes Neuland.

Antworten
  • Forum-Beiträge: 11

05.02.2016, 18:05:07 via Website

Gaaaaanz langsam lichtet sich der Nebel :D

aber jetzt sagt er mir bei

@Override
protected void onProgressUpdate(Boolean... values) {
   MyCoolListener.onPingResult(teststatus);
}

onPingResult is rot unterstrichen und in der Fehlerbeschreibung steht "Non-static method 'onPingResult(oolean)' cannot be referenced from a static context "
als lösungsvorschlag meint er 'Make onPingResult static' wenn ich das aber mach muss ich ja mein Override in der Activity auch static machen und wenn das dann static ist kann man wieder nicht auch Views zugreifen da das aus nem static context wiederum nicht geht.....

Antworten
  • Forum-Beiträge: 2.243

05.02.2016, 19:22:22 via Website

Wie ich sagte, du musst eine Instanz der Activity an den AsyncTask übergeben und als Klassenvariable speichern.

Schau Dir bitte nochmal mein Beispiel an und den Hinweis Klassen groß und Methoden klein zu schreiben.
In meinem Beispiel beginnt mListener mit einem Kleinbuchstaben, ist also KEIN Zugriff auf eine Klasse, sondern auf eine VARIABLE.

Antworten
  • Forum-Beiträge: 11

06.02.2016, 15:25:21 via Website

Es funktioniert!!!

Ich danke dir vielmals für deine Unterstützung (und vor allem für deine Geduld mit mir (laughing) )
Bei meinen nächsten Fragen (und die werden kommen) werde ich mich wieder an dich wenden.

Nur kleine frage dazu.... soll ich weitere Fragen die auch was anderes Beinhalten hier in dem Thread hier stellen oder dann nen neuen aufmachen?

Gruß und nochmal großes Dankeschön :)

Benjamin

Antworten
  • Forum-Beiträge: 22.353

06.02.2016, 17:41:13 via Website

Hallo Benjamin,

Da deine Frage hier beantwortet ist, hab ich mal einen Haken dran gemacht - für deine anderen Fragen machst du besser eigene Threads auf, dann findet man sie leichter wieder ;)

Viele Grüße,
Andy


OnePlus 3 (Resurrection Remix 5.8.2)
LG G Watch

Regeln | unsere Mods & Admins

Antworten

Empfohlene Artikel