ProgressDialog wird nicht/zu spät angezeigt?! (AsyncTask)

  • Antworten:22
Sebastian
  • Forum-Beiträge: 15

05.06.2014, 13:46:32 via Website

Hallo,

ich studiere Medieninformatik und muss für Android eine WM-App erstellen. Das ganze ist grundsätzlich nicht kompliziert: Die Activity hat ein ExpandableListView, welches die aktuellen Spielergebnisse unterteilt in Spieltage anzeigt. Die Daten kommen von einer API (JSON). Das funktioniert auch soweit.

Das Problem: Ich möchte beim Download einen ProgressDialog anzeigen lassen, welcher den Nutzer drauf hinweißt, dass gerade gedownloaded wird. Ist der Download vorbei soll dieser Dialog verschwinden. Ich versuche das schon seit einigen Tagen zu lösen, aber es funktioniert einfach nicht! Entweder der Dialog wird gar nicht angezeigt oder erst nach dem Download!

Die wichtigsten Klassen:

  1. OverviewActivity (initialisiert das ListView, Adapter etc.)
  2. ResultControler (kümmert sich um Download der Daten)
  3. DownloadTask [AsyncTask!] (bekommt einen Link und gibt den JSON-Code als String zurück)

Hier erstmal ein paar Codeauszüge:

zu 1.: die Initialisierung:

public class OverviewActivity extends Activity implements OnResultListener {

ExpandableListView resultList;
ResultListAdapter adapter;
ResultController resultController; 
OnResultListener resultListener;
ProgressDialog progressDia = new ProgressDialog(this);

AlertDialog.Builder alertDiaBuilder;

SparseArray<MatchDay> results = new SparseArray<MatchDay>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_overview);
    initProgressDia();
    initFunctions();        
    readOutData();
}

private void initFunctions() {
    initResultList();
    initResultController();
}

private void initResultList() {
    resultList = (ExpandableListView) findViewById(R.id.result_list);
    adapter = new ResultListAdapter(this, results);
    resultList.setAdapter(adapter); 
}

private void initResultController() {
    resultController = new ResultController(this, this);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();

    switch (id) {
    case R.id.menu_refresh_button:
        readOutData();
        break;
    }

    return true;
}

@Override
public void onUpdateInitiated() {
    Log.d("WM", "Start Download");
    progressDia.show();
}

@Override
public void onUpdateCanceled(int error) {
}

@Override
public void onUpdateCompleted() {
    Log.d("WM", "End Download");
    progressDia.dismiss();
}

@Override
public void onNewResults(SparseArray<MatchDay> results) {
    this.results = results;
    initResultList();
}

Hierzu muss ich sagen, über die Log-Ausgabe passiert genau das was ich will: Es wird genau dann angezeigt wenn der download beginnt, wenn er auch beginnt! Und wenn er endet! Leider funktioniert das mit dem ProgressDialog nicht! Kann mir jemand sagen warum das so ist?

zu 3.: Der AsyncTask:

public class DownloadTask extends AsyncTask<String, Integer, String> {

private String responseString;


@Override
protected String doInBackground(String... params) {
    this.responseString = processHttpRequest(params[0]);
    return responseString;
}

private String processHttpRequest(String url){
    HttpClient httpclient = new DefaultHttpClient();
    HttpResponse response;
    String responseString = null;

    try{
        response = httpclient.execute(new HttpGet(url));
        StatusLine statusLine = response.getStatusLine();

        if(statusLine.getStatusCode() == HttpStatus.SC_OK){
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            response.getEntity().writeTo(out);
            out.close();
            responseString = out.toString();
        } else {
            response.getEntity().getContent().close();
            throw new IOException(statusLine.getReasonPhrase());
        }
    } catch (Exception e) {
        Log.d("WM", "HTTP-Request-Error");
    }
    return responseString;      
}

}

Wo muss ich genau den ProgressDialog initialisieren und wie kann ich ihn wirklich VOR dem Download anzeigen lassen?
Ich bin am Verzweifeln... Wäre schön wenn mir jemand helfen könnte!

Danke!

Viele Grüße!

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

05.06.2014, 14:34:20 via Website

Ich würde den starten, wenn du mit dem Download beginnst, d.h. wenn du eine Instanz deines AsyncTasks erstellet und diese dann mit execute auführst.

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

Antworten
Sebastian
  • Forum-Beiträge: 15

05.06.2014, 15:56:00 via Website

Pascal P.

Ich würde den starten, wenn du mit dem Download beginnst, d.h. wenn du eine Instanz deines AsyncTasks erstellet und diese dann mit execute auführst.

Dann stürtzt die App vorzeitig ab... Ich verstehe nicht woran das liegt. Ich würde gerne einfach mit progressDia.show(); den Dialog anzeigen, aber noch nichtmal das funktioniert :(

Edit: Mir ist auch unklar, warum in der Log-Console "Start Download" und "End Download" genau zur richtigen Zeit ausgegeben wird. Der ProgressDialog aber erst kommt, wenn der Download abgeschlossen ist, obwohl beides in der gleichen Listener-Funktion steht...

— geändert am 05.06.2014, 15:58:50

Antworten
Georg C.
  • Forum-Beiträge: 235

05.06.2014, 23:56:10 via Website

Hi,
ich kenne mich zwar mit dem Sequentiellem Programmablauf bei Android noch nicht so gut aus, was mir aber eingefallen ist;
Du instanzierst schon in dem deklarationsfeld den ProgressDialog Objekt.

...
ResultController resultController; 
OnResultListener resultListener;
ProgressDialog progressDia = new ProgressDialog(this);

AlertDialog.Builder alertDiaBuilder;
...

und was in dem Zeitpunkt vermute NO GO ist, übergibst Du dem (ProgressDialog) mit this die Activity.
In dem Zeitpunkt weis noch nicht der "Teufel" was this IST!
Vermute, im Programmablauf, landet das ProgressDialog irgendwo ins nirvana ...

Zitat:

Wo muss ich genau den ProgressDialog initialisieren

Versuche erstmal in der onCreate(... Methode.
Die ist mit einem Konstruktor vergleichbar.

LG
Georg

EDIT
Nachtrag weil:
resultController = new ResultController(this, this);
Was das! -> Ist das Richtig?
(this, this);

_____________________

...
ResultController resultController; 
OnResultListener resultListener;
ProgressDialog progressDia;
AlertDialog.Builder alertDiaBuilder;
...

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_overview);
    initProgressDia(); // <---  wo ist die Methode?
    progressDia = new ProgressDialog(this);
    initFunctions();        
    readOutData();
}
...

— geändert am 06.06.2014, 00:16:35

Sorry für Gramatik & Stilistik Fehler.

Antworten
Sebastian
  • Forum-Beiträge: 15

06.06.2014, 09:01:50 via Website

Hallo,

dein Gedanke war nicht schlecht und erschien mir auch logisch - aber leider wird der ProgressDialog trotzdem gar nicht angezeigt. Noch nichtmal NACH dem Download... Genau das selbe passiert im übrigen auch mit einem AlertDialog. Er wird NACH dem Download angezeigt (sprich: App wird gestartet -> leere App -> paar Sekunden warten -> App wird kurze Zeit schwarz -> ExpendableListView mit Ergebnissen -> Dialog).

Es muss meines Erachtens wohl in irgendeiner Form daran liegen, dass die Dialoge erst angezeigt werden können, wenn die App komplett geladen ist.... Dialoge sind mir bei Android ein Rätsel...

initProgressDia(); // <---  wo ist die Methode?

Aus Platzgründen habe ich sie nicht gepostet. Dort wird dem ProgressDialog lediglich ein Titel und eine Message zugeordnet...

Viele Grüße!

-----------------------------------------------------------

Edit:

resultController = new ResultController(this, this);
Was das! -> Ist das Richtig?

Ja! Es wird nebem dem "Context" noch ein "Listener" übergeben. Aber trotzdem danke für den Hinweis!

— geändert am 06.06.2014, 09:04:01

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.06.2014, 09:56:07 via Website

Da brauchst du doch nich2 mal this übergeben.
1x This und dann in der Funktion dem Listener und Context zuorden (Casten)

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

Antworten
Sebastian
  • Forum-Beiträge: 15

06.06.2014, 10:18:20 via Website

Stimmt, du hast recht! Danke :-)

Aber die Funktion vom Dialog beeinflusst das ja nicht.... :(

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.06.2014, 10:37:15 via Website

Wie rufst du denn den dialog auf(kompletter Code für den Dialog)
Bitte mal posten

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

Antworten
Sebastian
  • Forum-Beiträge: 15

06.06.2014, 10:48:02 via Website

In der Methode initDialog(); wird er initiiert:

    pd = new ProgressDialog(this);
    pd.setTitle("Test");
    pd.setMessage("Loading....");

und aufgerufen wird er durch eine Listener-Methode:

public void onUpdateInitiated() {
    pd.show();
    Log.d("WM", "Start Download");
}

beendet wird er ebenfalls durch die Listener-Methode:

@Override
public void onUpdateCompleted() {
    pd.dismiss();
    Log.d("WM", "End Download");
}

Das alles geschieht in der OverviewActivity.java!
Hast du das gemeint? Wenn Code fehlt bitte einfach melden - ich bin für jede Hilfe dankbar!

Viele Grüße!

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.06.2014, 11:02:00 via Website

Den dialog rufst du schon aus dem MainThread und nichaus dem AsyncTask auf oder?

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

Antworten
Sebastian
  • Forum-Beiträge: 15

06.06.2014, 11:12:58 via Website

Ja, richtig! Ich möchte erstmal nur dass der Dialog angezeigt wird - erstmal ohne ProgressUpdate aus dem AsyncTask, ect...

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.06.2014, 14:20:09 via Website

Dann ist es klar, du musst den Dialog aus dem MainThread vor dem Startes des Taskes aufrufen.

Dialog.show();

new AsyncTask#execute(Parameters);

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

Antworten
Georg C.
  • Forum-Beiträge: 235

06.06.2014, 23:57:20 via Website

Junge Mann,
erstmall heiß Dein ProgressDialog -> progressDia
(ProgressDialog progressDia = new ProgressDialog(this); )
Jetzt heßt es (Dein ProgressDialog ) -> pd
(pd = new ProgressDialog(this); )
Und wie wird es bei der Frage 123 heißen?

Machmall PAUSE.

Schafe in Deinem Code Ordnung, setzte ein paar Breakpoints an relevanten stellen, und es wird funzen!
Obwohl ich vermute, dass Du den ProgressDialog in einen Thrad packen muss, und über ein Handler es visualisieren sollst.

Handler handler;
...
handler = new Handler();
...
handler.post(new Runnable() {
//@Override
public void run() {

// hier Dein ProgressDialog
 pd.show();                      
 }
});
...

Nun ob es richtig ist? -da bin ich wohl noch "zu klein".

LG
Georg

— geändert am 06.06.2014, 23:57:57

Sorry für Gramatik & Stilistik Fehler.

Antworten
Sebastian
  • Forum-Beiträge: 15

07.06.2014, 14:47:30 via Website

Pascal P.

Dann ist es klar, du musst den Dialog aus dem MainThread vor dem Startes des Taskes aufrufen.

Dialog.show();

new AsyncTask#execute(Parameters);

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_overview);
    initDialog();   
    initFunctions();    
    readOutData();
}

Auch wenn ich ihn in der Funktion "initDialog()" aufrufe (nach Initialisierung) wird er leider nicht angezeigt...

erstmall heiß Dein ProgressDialog -> progressDia
(ProgressDialog progressDia = new ProgressDialog(this); )
Jetzt heßt es (Dein ProgressDialog ) -> pd
(pd = new ProgressDialog(this); )

Das liegt daran, dass ich ihn ein paar mal neu implementiert habe - nachdem ich Tipps von euch erhalten habe... Wie er heißt ist ja erstmal egal, hauptsache ich habe innerhalb vom Code einen kosistenten Namen ;-)

Naja, es scheint bei mir nicht zu funktionieren.... Vielen Dank trotzdem für die Hilfe! Vielleicht bekommen wir ja im Laufe der nächsten Vorlesungen Tipps.

Viele Grüße!

Antworten
Andreas S.
  • Forum-Beiträge: 76

08.06.2014, 15:27:30 via Website

Die Klasse AsyncTask hat ja noch mehr Methoden als nur doInBackground..

onPreExecute --> hier ist man noch im UI-Thread, hier kannst du den ProgressDialog starten!

onPostExecute -> hier den Dialog entfernen -> also dismiss

Antworten
Sebastian
  • Forum-Beiträge: 15

09.06.2014, 10:49:21 via Website

Hallo,

wenn ich es so mache, wird in meinem Fall der ProgressDialog mehrmals hintereinander aufgerufen, weil mehrmals JSON-"Pakete" aus dem Internet abgerufen werden und jedesmal der AsyncTask für den Abruf gestartet wird...

Viele Grüße!

Antworten
Andreas S.
  • Forum-Beiträge: 76

09.06.2014, 13:23:18 via Website

Was spricht in deinem Fall dagegen alle Anfragen in einem AsyncTask auszuführen?

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

09.06.2014, 13:25:30 via Website

@Andreas:
Vielleicht, weil es einfacher zu Programmieren ist, da brauchst du nur einen PaketDownloader dem du dann die Url übergeben must.
Dann brauchst du einfach noch die Objekte anlegen.
Vlt. schaust du dir noch mal das OOP Prinzip an.

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

Antworten
Andreas S.
  • Forum-Beiträge: 76

09.06.2014, 13:33:22 via Website

Was hat das mit OOP zu tun?
Warum mehrere AsyncTasks hintereinander starten und jedem eine Url übergeben,
anstatt einfach einem AsyncTask zwanzig Urls zu übergeben?
Als Ergebnis hat er dann halt 20 JSON-Objekte.

Aus dem hier:

@Override
protected String doInBackground(String... params) {
    this.responseString = processHttpRequest(params[0]);
    return responseString;
}

das hier:

@Override
protected String doInBackground(String... params) {
    ArrayList<String> results = new ArrayList<String>();
    for(String p : params){
       try{
          results.add(processHttpRequest(p));
       }catch(IOException ex){
           //iwie loggen
       }
    }
    return results;
}

— geändert am 09.06.2014, 13:41:35

Antworten
Sebastian
  • Forum-Beiträge: 15

12.06.2014, 08:56:07 via Website

Genau den Gedanken hatte ich auch, habe ihn auch letzte Woche schon umgesetzt und hat auch genauso funktioniert! Nur leider konnte ich im AsyncTask keinen ProgressDialog initialisieren und ausgeben... Irgendetwas mache ich falsch! Ich hoffe dauernd, dass das nochmal in der Vorlesung behandelt wird, aber die fällt dauernd aus!!! :(

Viele Dank nochmal!

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

12.06.2014, 10:18:09 via Website

Ich habe schon mal gesagt, dass du in einem Async Task keinen PrograssDialog initialisieren kannst, da dieser in einem anderen Thread läuft.
Initialisieren musst du außerhalb des AsyncTasks oder mit RunOnUiThread oder in der onpostCreate etc.
Mach es doch einfach vor dem Starten des Tasks und beende den Task wenn der AsyncTask fertig ist

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

Antworten
Andreas S.
  • Forum-Beiträge: 76

12.06.2014, 19:40:01 via App

Stimmt so nicht ganz, die Klasse AsyncTask besitzt die Methode onPreExecute.
diese wird vor doInBackground aufgerufen und läuft unter dem ui thread

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

13.06.2014, 11:13:37 via Website

@Andreas: Stimmt, aber mit AsyncTask bringe ich Threading etc. in Verbindung, der Dialog darf nur in der doInBackground Methode nicht aufgerufen werden.

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

Antworten