web-dev-qa-db-fra.com

Android appelle AsyncTask juste après un autre terminé

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 

27
hcpeter

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
        }
      }
   }); 
26
ρяσѕρєя K

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);
21
Peter Ajtai

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.

4
waqaslam
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();
                }
            }
        }
    }

}
1
CooL AndroDev

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.

1
Alex Gitelman

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!

0

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();
        }
}
0
AmirHossein Manian