J'ai un problème avec Android AsyncTask. Il y a une activité qui contient du TextView, un bouton et une image. Lorsqu'un utilisateur entre cette activité, je commence une tâche asynchrone pour vérifier si l'utilisateur peut y aller depuis l'activité (jusqu'à ce que la tâche ne termine pas le bouton inactif). Ensuite, je veux commencer une autre tâche asynchrone pour obtenir l'image. Alors j'ai fait une classe intérieure:
AsyncTask<String, Void, JSONObject>() authTask = new AsyncTask<String, Void, JSONObject>() {
@Override
protected JSONObject doInBackground(String... params) {
//call the rest api
}
@Override
protected void onPostExecute(JSONObject result) {
// check the result
// and make another asynctask
AsyncTask<String, Void, Bitmap> imageTask = new Async.... {
// get image
}
imageTask.execute();
}
}
et j'appelle authTask.execute();
à partir du thread d'interface utilisateur.
J'ai un mauvais pressentiment à ce sujet, en particulier il semble que cela ne fonctionne pas (ça va, mais quelques fois, ça "gèle": aucune exception n'est suspendue et la barre de progression tourne. Rien ne se passe et le bouton ne sera pas actif.) Il y a un autre moyen d'obtenir une information et quand c'est fini, on commence immédiatement une autre tâche?
UDPATE: Je travaille avec api niveau 10. Dans authTask, je reçois des informations nécessaires au démarrage de imageTask (un identifiant), je dois donc appeler ces tâches à la suite. En api niveau 10 c'est possible?
Merci d'avance!
Frère Peter
vous pouvez utiliser getStatus()
pour vérifier si la AsyncTask
est en attente, en cours d'exécution ou terminée. et lorsque finsh commence votre nouvelle tâche
if(authTask .getStatus() == AsyncTask.Status.PENDING){
// My AsyncTask has not started yet
}
if(authTask .getStatus() == AsyncTask.Status.RUNNING){
// My AsyncTask is currently doing work in doInBackground()
}
if(authTask .getStatus() == AsyncTask.Status.FINISHED){
// START NEW TASK HERE
}
exemple pour votre application:
btn.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
if (authTask != null && authTask.getStatus() == AsyncTask.Status.FINISHED) {
//START YOUR NEW TASK HERE
}
else
{
//IGNORE BUTTON CLICK
}
}
});
1:
Vous pouvez écrire le code pour authTask puis pour imageTask, l'un après l'autre, dans une seule doInBackground()
. Cette instance AsyncTask unique serait déclenchée par une seule instruction execute()
. Cela peut être ou ne pas être pratique en fonction des interactions d'interface utilisateur nécessaires.
2:
Edit: comme l'a noté kabuku, cette information est principalement pour HoneyComb +. Pre HoneyComb Je voudrais certainement aller avec l'option 1 ci-dessus. executeOnExecutor () est un niveau d'api supérieur ou égal à 11
Dans les versions reçues, execute()
enverra vos tâches asynchrones en série par défaut (ICS +). Si vous voulez vous assurer que cela se produit, spécifiez l'exécuteur série.
Dans votre cas, ce serait:
authTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
// Image task will only be done AFTER textViewTask is done
imageTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
Et pour les nouvelles versions un simple
...
// ICS+ and pre honeycomb (I think)
authTask.execute();
// Image task will only be done AFTER textViewTask is done
imageTask.execute();
...
Dans la documentation AsycnTask.execute ():
Remarque: cette fonction planifie la tâche dans une file d'attente pour un seul thread d'arrière-plan ou pool de threads selon la plate-forme version. Lors de la première introduction, les AsyncTasks étaient exécutées en série sur un fil de fond unique. En commençant par DONUT, cela a été changé en pool de threads permettant à plusieurs tâches de fonctionner en parallèle. Après HONEYCOMB, il est prévu de revenir à un seul thread en éviter les erreurs d'application courantes causées par l'exécution en parallèle.
PS: Pour exécuter des tâches indépendantes les unes des autres, vous devez utiliser le AsyncTask.THREAD_POOL_EXECUTOR
. Cela nécessite un exécuteur différent:
// Go parallel! (NOT what you want)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Ce n'est pas une bonne conception pour imbriquer AsyncTask. Faites tout le travail lourd dans doInBackground et postez/mettez à jour les résultats. En d'autres termes, combinez le traitement de la deuxième tâche Async dans la première.
int count;
private void attemptConnect()
{
count = 0;
str_lang = "English";
str_wait = "Plaese Wait";
new AllQuestion().execute();
}
private class AllQuestion extends AsyncTask<String, String, String> {
ProgressDialog pg;
@Override
protected void onPreExecute() {
super.onPreExecute();
pg = new ProgressDialog(LanguageActivity.this);
pg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pg.setMessage(str_wait);
pg.setCancelable(false);
pg.show();
}
@Override
protected String doInBackground(String... strings) {
try {
SoapObject soapObject = new SoapObject(AppConstant.NAMESPACE, AppConstant.QUESTION_SOAP_METHOD);
soapObject.addProperty("language", str_lang);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(soapObject);
HttpTransportSE se = new HttpTransportSE(AppConstant.webUrl);
se.call(AppConstant.QUESTION_SOAP_ACTION, envelope);
Object responce = envelope.getResponse();
Log.d("Question List:=>>", "" + responce);
return responce.toString();
} catch (Exception e) {
e.printStackTrace();
pg.dismiss();
return null;
}
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (pg.isShowing()) {
pg.dismiss();
Log.i(TAG, s);
if (s != null || !s.equalsIgnoreCase("")) {
try {
JSONArray array = new JSONArray(s);
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
String queId = obj.getString(TAG_QID);
String que = obj.getString(TAG_QUE);
String str_Opt = obj.getString(TAG_OPT);
question = new Question(queId, que, str_lang, str_catId, str_Opt, manager.getDateTime());
helper.insertQuestion(question);
}
count++;
if (count < 5) {
if (count == 1) {
str_lang = "German";
str_wait = "bitte warte einen Moment";
new AllQuestion().execute();
}
if (count == 2) {
str_lang = "Italian";
str_wait = "per favore aspetta un momento";
new AllQuestion().execute();
}
if (count == 3) {
str_lang = "Chinese";
str_wait = "请稍候";
new AllQuestion().execute();
}
if (count == 4) {
str_lang = "French";
str_wait = "patientez s'il-vous-plait";
new AllQuestion().execute();
}
Log.d("All Question:-", question.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}
D'après le code que vous avez montré, il ne semble pas logique de créer une deuxième tâche. Obtenez juste votre image dans doInBackground
de la première tâche juste après autorisation .. Si vous devez mettre à jour l’UI entre les deux, vous pouvez le faire dans la mise à jour en cours.
J'ai résolu ce genre de problème quand je devais télécharger quelque chose d'une base de données avant de me connecter à l'utilisateur dans l'application, avec ceci j'ai corrigé ce problème.
Pour utiliser ObservableInteger
, vous pouvez le faire
d'abord le déclarer
private ObservableInteger mObsInt;
alors, dans votre onCreate, un auditeur attendra que les valeurs de mObsInt changent, et que ces valeurs changent, vous pouvez faire tout ce que vous voulez.
//Listener
mObsInt = new ObservableInteger();
mObsInt.set(0);
mObsInt.setOnIntegerChangeListener(new OnIntegerChangeListener()
{
@Override
public void onIntegerChanged(int newValue)
{
if (mObsInt.get()==1)
//Do something if the first asyncTask finishes
if (mObsInt.get()==2){
//Do something if the second asyncTask finishes, in this case i just go to another activity when both asyncTasks finish
Intent mainIntent = new Intent().setClass(LoginActivity.this, Principal.class);
startActivity(mainIntent);
finish();
}
}
});
Alors, comment ça marche
ObservableInteger
cherchera des modifications dans la variable mObsInt
, alors disons que si mObsInt
est égal à 1 il fera quelque chose, si est égal à 2 fera autre chose, donc, résoudre ce problème avec 2 asynctasks
est facile, quand la asynctasks
termine mObsInt
sera égal à 1, si l'autre asyncTask
termine donc mObsInt
sera mObsInt++
, et votre mObsInt
sera égal à 2, l'auditeur attendra les valeurs, puis fera ce que vous voulez faire les valeurs correspondent à votre déclaration si à la méthode onCreate
maintenant, dans vos tâches asynchrones, il suffit de mettre cette ligne dans votre méthode onPostExecute ()
mObsInt.set(mObsInt.get()+1);
donc, si la première arrivée asynchrone se termine, mObsint == 1, si la deuxième finit mObsInt == 2 et que vous gérez ce que vous voulez faire dans votre méthode onCreate
espérons que cela vous aide, cela m'a aidé
Vous pouvez obtenir plus d'informations à ce doc: https://developer.Android.com/reference/Android/databinding/ObservableInt.html
bonne codage!
J'ai une idée pour faire des séries asynchrones en une seule tâche asynchrone :
protected Boolean doInBackground(String... params) {
if(params[0] == "taskA") {
//do somthing
params[0] = "taskB";
}
if(params[0] == "taskB") {
//do somthing
params[0] = "taskC";
}
if(params[0] == "taskC") {
//do somthing
params[0] = "taskD";
}
if(params[0] == "taskD") {
//do somthing
return true;
}
Et dans votre fil principal, appelez simplement une tâche asynchrone comme ceci:
ShowMyProgress(); //if you like
new MyAsyncTask().execute("taskA");
Et enfin, vous pouvez masquer vos progrès sur onPostExecute comme:
protected void onPostExecute(final Boolean success) {
if (success) {
....
HideMyProgress();
}
}