[ERLEDIGT] Problem mit Async Task und auszuführender Aufgabe

lordzwieback

lordzwieback

Erfahrenes Mitglied
210
Moin miteinander,

ich habe ein kleines (Gedanken)Problem mit einer Abfrage. Folgendes Szenario: Form mit Eingaben (TextEdits), die der User tätigen kann. Ebenso kann man über zwei Buttons vor und zurück springen durch die Datensätze.

Nun wollte ich einen Dialog anzeigen, wenn ungespeicherte Daten vorhanden sind, aber schon jemand auf den nächsten Datensatz springen will. Dieser Dialog funktioniert auch. Nur habe ich das Problem, dass während der Dialog angezeigt wird schon die nachfolgenden Zeilen Code ausgeführt werden.

Um das zu verhindern, wollte ich den Dialog in ein Async Task stecken, da ich hier davon ausgehen kann, dass der Task zuerst komplett ausgeführt wird, bevor weiter Code abgearbeitet wird. Jetzt habe ich aber das Problem, dass ich meine TEMP-Werte mit den aktuellen Werten aus den EditTexts vergleichen muss, um festzustellen, ob ungespeicherte Daten vorhanden sind. Ich kann aber aus dem AsyncTask doInBackground keine UI-Elemente ansprechen... kenn ich mich jetzt nicht gut genug mit den Asyncs aus oder hat jemand vielleicht einen Tipp für mich?

Die Werte im OnPreExecute setzen und dem doInBackground bzw. OnPostExecute weitergeben hat nicht funktioniert - vielleicht habe ich auch etwas falsch gemacht.

Hier mal noch der Dialog:
Code:
AlertDialog saveAlert = new AlertDialog.Builder(MainActivity.this).create();
saveAlert.setTitle("Ungespeicherte Eingaben");
saveAlert.setMessage("Es sind ungespeicherte Änderungen am aktuellen Datensatz vorhanden.\n\n Möchten Sie speichern?");
saveAlert.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
        save();
    }
});
saveAlert.setButton(DialogInterface.BUTTON_NEGATIVE, "Abbrechen", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
        return;
    }
});
saveAlert.show();
 
Habe ich das richtig verstanden: du hast eine Form mit mehreren EditTexts und kannst mit den 2 Buttons zwischen diesen vor- und zurückspringen? Wenn ja, verstehe ich nicht genau wofür die Buttons da sind, da der User ja einfach in ein beliebiges EditText reintippen kann.

Nutzt du ein TextInputLayout?
 
Aufs einfachste runtergebrochen habe ich hier eine Activity, die mit diversen Elementen (EditText, RadioGroups usw) einen Datensatz darstellt. Mit den "vor" und zurück" Buttons wechsle ich zum nächsten oder vorherigen Datensatz.
 
Ok, aber tust du das ganze nicht am Ende erst auswerten? Also sagen wir mal der Nutzer drückt wenn er fertig ist auf "Abschicken". Wenn du die Daten erst dann evaluierst, dann brauchst du auch keinen AsyncTask. Funktioniert z.B. mit dem TextInputLayout sehr gut.
 
Ich glaube wir reden aneinander vorbei. Wieso sollte jemand X Datensätze bearbeiten und dann nach dem Xten Datensatz erst speichern, und zwar alle?

deka schrieb:
Also sagen wir mal der Nutzer drückt wenn er fertig ist auf "Abschicken"
Genau deswegen will ich ja die Abfrage. Natürlich gibts einen Speichern Button, aber wenn man zu fix ist klickt man auf den nächsten und es wird nicht gespeichert. Ebenso bescheuert wäre es, beim Klick auf den nächsten DS einfach automatisch zu speichern, da man ja nicht weiß, ob es beabsichtigt ist.
 
Du solltest wenn du den Dialog anzeigst einfach NICHT die eigetnlich Aktion des Buttons ausführen.
PseudoCode:
Code:
public onClick(Button weiterButton) {
  if (changed) {
    dialog = ...
    dialog.okButton.onClicklistener = {
      doSave();
      doWeiter();
    }
  } else {
    doWeiter();
  }
}

Kein AsyncTask notwendig.
Dann bleibst du solange auf diesem Datensatz bis auch wirlich gespeichert oder abgebrochen wurde.
 
  • Danke
Reaktionen: lordzwieback
@deek Sorry dass ich erst jetzt antworte, war gestern bis spät abends unterwegs und hatte dann keinen Nerv mehr.

Danke für dein Beispiel. Soll also heißen ich hätte z.B. eine Funktion, die mir einen boolschen Wert zurückliefert (changed), welcher mir dann anzeigt, ob etwas geändert wurde oder nicht. Diese Methode rufe ich vor der Abfrage auf und je nachdem, was zurückkommt, wird dann der Dialog angezeigt oder eben nicht. Werde das im Laufe des Tages mal ausprobieren, danke.
[doublepost=1493797108,1493793716][/doublepost]Hat funktioniert dank deines Tipps. Hier meine Lösung:

Funktion zum Prüfen, ob Daten verändert wurden
Code:
public Boolean changedData() {
        if(!tmpMangel.equals(maengel.getText().toString()) || tmpErgebnis != ergebnis.getCheckedRadioButtonId()) {
            return true;
        } else {
            return false;
        }
    }

Hier mein Code für die Buttons
Code:
// Button NEXT INSPECTION
                    next.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            // check if required fields are not empty
                            if(mitMaengel.isChecked() && maengel.getText().toString().equals("")) {
                                Toast.makeText(getApplicationContext(), "Bitte Mangel eintragen", Toast.LENGTH_SHORT).show();
                                return;
                            }
                            changedData = changedData();
                            if(changedData) {
                                AlertDialog saveAlert = new AlertDialog.Builder(MainActivity.this).create();
                                saveAlert.setTitle("Ungespeicherte Eingaben");
                                saveAlert.setMessage("Es sind ungespeicherte Änderungen am aktuellen Datensatz vorhanden.\n\n Möchten Sie speichern?");
                                saveAlert.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialogInterface, int i) {
                                        save();
                                        listPointer += 1;
                                        handleButtons(listPointer, listSize);
                                        setValues(listPointer);
                                    }
                                });
                                saveAlert.setButton(DialogInterface.BUTTON_NEGATIVE, "Abbrechen", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialogInterface, int i) {
                                        listPointer += 1;
                                        handleButtons(listPointer, listSize);
                                        setValues(listPointer);
                                    }
                                });
                                saveAlert.show();
                            } else {
                                listPointer += 1;
                                handleButtons(listPointer, listSize);
                                setValues(listPointer);
                            }
                        }
                    });
Beim Button fürs Zurückspringen wird natürlich listPointer += 1; durch listPointer -=1 ersetzt.
 
Freut mich, dass du es hinbekommen hast. Haben gestern ja leider aneinander vorbeigeredet :) Aber das du keinen AsynTask dafür brauchst war mir eigentlich schon gleich klar. Noch ein kleiner Tipp: in der Methode changedData() kannst du den else-Block rausschmeißen und einfach nur das return false stehen lassen. Nur mal so zur Vereinfachung.
 
@deka stimmt, das mit dem else-Zweig vergesse ich immer ... alte Angewohnheiten kriegt man schwer raus. :D
 
@deka @lordzwieback Wenn wir schon beim optimieren sind:
Code:
public Boolean changedData() {
       return (!tmpMangel.equals(maengel.getText().toString()) || tmpErgebnis != ergebnis.getCheckedRadioButtonId());
}
und
Code:
changedData = changedData(); <---weg
                           if(changedData()) { <--- als Methodenaufruf

;)

Freut mich, dass ich helfen konnte.
 
  • Danke
Reaktionen: lordzwieback
@deek Ich bin auch noch nicht so lange im Geschäft und betreibe das ganze größtenteils bisher als Hobby nebenbei. Wenn ich mir manche Sachen nicht explizit so schreibe, wie ich es momentan mache, verliere ich den Überblick, so dumm das auch klingen mag (bezogen auf deine erste Optimierung). Das zweite leuchtet mir aber ein und werde ich mal umstellen.

Bitte nicht falsch auffassen á la "Der Depp nimmt meine guten Tipps nichts an". Vielleicht komme ich noch an den Punkt, wo jede Zeile zählt. Momentan behalte ich es mir aber der Übersicht halber vor, das Ganze besser ausführlich zu machen als nur zu schauen, dass alles mit möglichst wenig Zeilen klappt und möglichst optimiert ist. :D

Dir trotzdem danke, werds mir zu Herzen nehmen :)
 
@lordzwieback
Das machst du auch richtig so. Erst einmal sollte dein Code funktionieren bzw. nachvollziehbar sein und im nächsten Schritt kannst du deinen Code optimieren (refactoring).

Edit:

Was ich dir auch noch empfehlen kann: lege dich auf eine Sprache fest für die Variablen, Methoden, Kommentare etc.. Bei dir ist es aktuell noch gemischt. Am Besten immer alles auf englisch, da der Code ja sowieso englisch ist. Liest sich leichter :)
 
Halte meinen Code in den meisten Fällen zu 98% englisch. Alles andere ist nur zur "extremen" Verdeutlichung der Zusammenhänge, da ich auf lange Sicht wohl nicht der einzige bin, der mal an den Code der App muss. :)
 
@lordzwieback War ja auch eher mit dem Zwinkersmiley zu sehen. Ich lasse solche If/else return statements auch oft stehen, weil es übersichtlicher ist. Kein Stress ich nehm das nicht krumm.
 
  • Danke
Reaktionen: lordzwieback
@deek @deka

Sorry dass ich euch hier nochmal tagge, aber habe schon wieder ein kleines Problemchen und denke, es ist so ähnlich, da braucht es keinen neuen Thread.

Es geht wieder um einen Dialog, wieder um nicht gespeicherte Inhalte. Ich habe einen Spinner. Für diesen Spinner habe ich ein setOnItemSelectedListener und in diesem ein onItemSelected.

Im onItemSelected soll direkt am Anfang gecheckt werden, ob Daten verändert wurden. Das funktioniert auch alles ganz toll. Hier der Dialog:
Code:
if(!Singleton.getInstance().getAppstartup()) {
                        changedData = changedData();
                        if (changedData) {
                            AlertDialog saveAlert = new AlertDialog.Builder(MainActivity.this).create();
                            saveAlert.setTitle("Ungespeicherte Eingaben");
                            saveAlert.setMessage("Es sind ungespeicherte Änderungen am aktuellen Datensatz vorhanden.\n\n Möchten Sie speichern?");
                            saveAlert.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    save();
                                }
                            });
                            saveAlert.setButton(DialogInterface.BUTTON_NEGATIVE, "Abbrechen", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    Toast.makeText(getApplicationContext(), "Änderungen wurden nicht gespeichert", Toast.LENGTH_SHORT).show();
                                }
                            });
                            saveAlert.show();
                        }
                    }

Direkt danach folgt Code, der die neu ausgewählte Datei (der Spinner enthält versch. Dateien, welche Datensätze enthalten) einliest und die Daten ins UI einträgt. Jetzt habe ich das Problem, dass zwar der Dialog in den richtigen Situationen angezeigt wird, aber im Hintergrund schon der Code zum Auslesen und Anzeigen der neuen Datensätze ausgeführt wird. Somit wird beim Click des OK Buttons nicht der ursprüngliche Datensatz gespeichert, sondern der neu aufgerufene.

Der Code zum Neueinlesen der ausgewählten Datei muss immer ausgeführt werden, egal ob der Dialog angezeigt wird oder nicht. Von daher weiß ich gerade nicht, wie ich hier korrekt vorgehen sollte. Sorry schonmal, falls die Lösung eigentlich offensichtlich ist...
 
Kannst du mal den weiteren Codeausschnitt zeigen. Du schreibst ja, dass direkt danach der Teil folgt, bei dem du den neuen Datensatz ausliest. Normalerweise sollte es ja so funktionieren, dass er die Antwort von deinem Nutzer abwartet. Und erst wenn er auf Ok oder Abbrechen geklickt hat wird der nächste Datensatz geladen.

Du kannst dir auch immer die Position deines Datensatzes merken und in einer HashMap abspeichern. Der Key ist dann die Position und Value ist dein Datensatz.
 
Das Problem ist wohl, dass Android hingeht und Dialoge nicht modal darstellt. D.h. dass der Dialog nie die UI Schicht blockiert/blockieren darf und deshalb der restliche Code einfach hinter dem Dialog weiterläuft. (Soweit meine Recherche bisher)

Das ist der Code zum Datei einlesen und Werte setzen.
Code:
                    listPointer = 0;
                    fileName = sItems.getSelectedItem().toString();
                    fileNameLength = fileName.length();

                    // read content of selected file
                    fList.clear(); // clear ArrayList before write new content by switching source file
                    try {
                        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(programFolder + "/" + sItems.getSelectedItem().toString()), "UTF-8"));
                        file = programFolder + "/" + sItems.getSelectedItem().toString();
                        String line;

                        while((line = br.readLine()) != null) {
                            fList.add(line);
                        }
                        br.close();
                    }catch(Exception e) {
                        Log.e(TAG, "Error: cant read file\ne: " + e);
                    }
                    listSize = fList.size();
                    // set values with method 'setValues', depending on listPointer value (see above)
                    handleButtons(listPointer, listSize);
                    setValues(listPointer);
 
Kommt dieser Teil direkt nach deinem ersten Codeteil? Muss das Gesamte mal sehen :)
 
Haha, ja sorry. Hier nochmal das Ganze:
Code:
@Override
                public void onItemSelected(AdapterView<?> adapterView, View selectedItemView, int position, long id) {
                    // if appstartup is false, do saveCheck
                    if(!Singleton.getInstance().getAppstartup()) {
                        changedData = changedData();
                        if (changedData) {
                            AlertDialog saveAlert = new AlertDialog.Builder(MainActivity.this).create();
                            saveAlert.setTitle("Ungespeicherte Eingaben");
                            saveAlert.setMessage("Es sind ungespeicherte Änderungen am aktuellen Datensatz vorhanden.\n\n Möchten Sie speichern?");
                            saveAlert.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    save();
                                }
                            });
                            saveAlert.setButton(DialogInterface.BUTTON_NEGATIVE, "Abbrechen", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    Toast.makeText(getApplicationContext(), "Änderungen wurden nicht gespeichert", Toast.LENGTH_SHORT).show();
                                }
                            });
                            saveAlert.show();
                        }
                    }

                    listPointer = 0;
                    fileName = sItems.getSelectedItem().toString();
                    fileNameLength = fileName.length();

                    // read content of selected file
                    fList.clear(); // clear ArrayList before write new content by switching source file
                    try {
                        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(programFolder + "/" + sItems.getSelectedItem().toString()), "UTF-8"));
                        file = programFolder + "/" + sItems.getSelectedItem().toString();
                        String line;

                        while((line = br.readLine()) != null) {
                            fList.add(line);
                        }
                        br.close();
                    }catch(Exception e) {
                        Log.e(TAG, "Error: cant read file\ne: " + e);
                    }
                    listSize = fList.size();
                    // set values with method 'setValues', depending on listPointer value (see above)
                    handleButtons(listPointer, listSize);
                    setValues(listPointer);
            }
 
Da du ja auch das Einlesen in der OnItemSelected machst, führt er den Teil auch immer direkt aus. Er wartet nicht so lange bis der User auf einen der Buttons klickt, sondern macht direkt weiter mit dem Einlesen. Ich würde das Einlesen in eine eigene Methode (z.B. readData()) auslagern und mit einem boolean flag arbeiten. Und erst wenn der AlertDialog geschlossen wurde vom Nutzer die Daten einlesen. Das ist mir so mal auf die Schnelle als erster Ansatz eingefallen.

Code:
 if (!Singleton.getInstance().getAppstartup()) {
            changedData = changedData();
            if (changedData) {
                alertDialogOpen == true;
                AlertDialog saveAlert = new AlertDialog.Builder(MainActivity.this).create();
                saveAlert.setTitle("Ungespeicherte Eingaben");
                saveAlert.setMessage("Es sind ungespeicherte Änderungen am aktuellen Datensatz vorhanden.\n\n Möchten Sie speichern?");
                saveAlert.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        save();
                        alertDialogOpen == false;
                    }
                });
                saveAlert.setButton(DialogInterface.BUTTON_NEGATIVE, "Abbrechen", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        Toast.makeText(getApplicationContext(), "Änderungen wurden nicht gespeichert", Toast.LENGTH_SHORT).show();
                        alertDialogOpen == false;
                    }
                });
                saveAlert.show();
            }
        }

        if(!alertDialogOpen){
            readData();
        }
 

Ähnliche Themen

S
Antworten
4
Aufrufe
944
Sempervivum
S
B
Antworten
4
Aufrufe
406
bb321
B
R
Antworten
3
Aufrufe
1.564
Ritartet
R
Zurück
Oben Unten