ProgressDialog dans Android AsyncTask ne s'affiche pas au bon moment
donc j'ai ces appels de serveur de longue durée sur ce qui est essentiellement OData en cours dans mon application Android. Le consommateur des appels utilise .execute().get()
pour attendre la réponse du thread réseau (je sais que la bonne façon est de rendre le tout asynchrone et basé sur le rappel, mais l'application ne peut fonctionner en aucune façon sans ces données, et complètement réarchitecter pour fonctionner de cette façon ne semble pas fournir d'avantages).
donc j'ai trouvé beaucoup les extraits en ligne où l'utilisation du ProgressDialog
en combinaison avec onPreExecute()
et onPostExecute()
comme montré dans l'exemple de code ci-dessous peuvent être utilisés pour afficher une boîte de dialogue de progrès tandis que le AsyncTask
exécute. J'utilise exactement les échantillons fournis, mais ce qui se passe c'est que l'appel commence, il attend la transaction réseau, puis très clignote rapidement et cache la boîte de dialogue Progression. Il peut s'asseoir pendant des secondes entières attendant la transaction et je sais pour un fait qu'il est en attente dans le doInBackground()
, mais le dialogue ne sera pas pop up jusqu'à la fin, ce qui le rend effectivement inutile.
dans le code au-dessous du bit DoEvents()
est fondamentalement juste un sommeil très court. J'ai essayé avec et sans Et il ne semble pas y avoir de différence, mais ça semblait intéressant d'essayer.
class GetFromServerTask extends AsyncTask<String, Void, String>
{
private Context context;
private ProgressDialog dialog;
public GetFromServerTask(Context ctx) {
context = ctx;
dialog = new ProgressDialog(ctx);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
dialog.setMessage("Loading...");
dialog.show();
DoEvents();
}
@Override
protected String doInBackground(String... parms) {
if(InOfflineMode)
return "notdeserializable";
String url = parms[0];
HttpURLConnection urlConnection = null;
try {
URL typedUrl = new URL(url);
urlConnection = (HttpURLConnection) typedUrl.openConnection();
//Add Authorization token
if(InDebugMode) {
urlConnection.addRequestProperty("AuthToken", AuthToken);
} else {
urlConnection.addRequestProperty("Authorization", "Bearer " + AuthToken);
}
urlConnection.addRequestProperty("Accept", "application/json");
DoEvents();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
byte[] contents = new byte[in.available()];
int bytesRead = 0;
String strContents = "";
while((bytesRead = in.read(contents)) != -1){
strContents += new String(contents, 0, bytesRead);
DoEvents();
}
if(strContents.startsWith("<HTML>"))
return "Error: Received unexpected HTML when connecting to service. Make sure you are not connected to a WIFI that requires authentication.";
return strContents;
} catch(UnknownHostException hex) {
return "Error: Could not find server address. Make sure you are connected to the internet. If you just changed connections (ie: turning WIFI on or off) it make take a minute to refresh";
}
catch(Exception ex) {
String msg = "Error: " + ex.getClass().getName() + ": " + ex.getMessage();
Log.e("TE", msg);
return msg;
} finally {
if(urlConnection != null)
urlConnection.disconnect();
}
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(dialog != null && dialog.isShowing())
dialog.dismiss();
DoEvents();
}
}
j'ai également essayé la version légèrement différente suggérée ailleurs sur SO (ci-dessous) avec les mêmes résultats exacts:
protected void onPreExecute() {
dialog=ProgressDialog.show(context, "", "Loading...", true, false);
super.onPreExecute();
}
j'ai également essayé de prendre le ProgressDialog
sur le AsyncTask
tous ensemble et de le montrer" en dehors " de la tâche, comme indiqué ci-dessous. Dans ce cas, il n'apparaît même pas.
ProgressDialog dialog = ProgressDialog.show(ServerAccessLayer.m_context, "", "Loading...", true, false);
String retVal = new GetFromServerTask(ServerAccessLayer.m_context).execute(url).get();
dialog.dismiss();
return retVal;
2 réponses
Ok, votre problème est votre .get()
. .get
est un appel de blocage. Cela signifie que vous ne retournerez pas à la boucle d'événements (le code dans le cadre Android qui appelle onCreate
, onPause
, les gestionnaires d'événements, onPostExecute
, onPreExecute
, etc) jusqu'à ce qu'il revienne. Si vous ne retournez pas à la boucle event, vous n'entrerez jamais dans le code de dessin, et vous n'afficherez pas la boîte de dialogue progress. Si vous voulez afficher la boîte de dialogue, vous devez réarchitecter votre application pour réellement utiliser le tâche de manière asynchrone. Note-si vous appelez .get()
comme ça sur votre interface utilisateur, votre application entière va geler et avoir l'air cassée. C'est pourquoi ils ont forcé les gens à ne pas faire de réseau IO sur le fil UI en premier lieu.
comme le dit @Gabe-Sechan, le .get()
est la raison pour laquelle votre UI gèle et votre ProgressDialog ne se montre pas comme vous voulez. D'un autre côté, Je ne suis pas d'accord avec lui quand il dit:
si vous voulez afficher le dialogue, vous devez réarchitecter votre application à utilisez la tâche de façon asynchrone.
si vous supprimez simplement votre .get()
et vous laissez dialogue Afficher dans le onPreExecute()
et de rejeter dans le onPostExecute(String result)
, vous obtiendrez ce que vous recherchez: un ProgressDialog affiché pendant que la tâche est exécutée.
mise à jour:
j'ai commencé une question basée sur le sens/l'utilité d'utiliser la méthode get()
de la classe AsyncTask D'Android.