Вопрос по android, android-asynctask – Android вызывает AsyncTask сразу после завершения другого

27

У меня проблемы с Android AsyncTask. Существует Activity, которая содержит некоторые TextView кнопку и изображение. Когда пользователь входит в это действие, я запускаю асинхронную задачу, чтобы проверить, может ли пользователь перейти от действия (пока задача не завершит, кнопка не активна). Затем я хочу начать еще одну асинхронную задачу, чтобы получить картину. Итак, я сделал внутренний класс:

<code>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();
     }
}
</code>

и я звонюauthTask.execute(); из пользовательского интерфейса.

У меня плохое предчувствие по этому поводу, тем более, что оно, кажется, не работает (это нормально несколько раз, но внезапно оно «зависает»: не исключение, просто зависание и вращение индикатора выполнения. Ничего не происходит, и кнопка не будет активной. ) Есть еще один способ получить информацию, и когда она будет закончена, немедленно запустите другое задание?

UDPATE: я работаю с API уровня 10. В authTask я получаю некоторую информацию, которая необходима для запуска imageTask (некоторый идентификатор), поэтому я должен вызывать эти задачи подряд. В API уровне 10 это возможно?

Заранее спасибо

Br, Питер

Вы уверены, что задание авторизации действительно завершено? Может быть, из-за длительного таймаута htt Renard
Да, я пытался отладить и не могу воспроизвести проблему во время отладки ... Другая вещь - это тайм-аут. Я установил разумное время ожидания, но это причина и еще один баг другого класса. (Скорее всего, это плохо, нужно дальнейшее расследование.) hcpeter
Я предполагаю, что вы отладили биты вdoInBackground что может висеть почти бесконечно? Используете ли вы тайм-ауты, которые являются разумными при вызове вашего REST API? Как правило, единственное требование дляAsyncTask это то, что вы создаете его в потоке пользовательского интерфейса, который вы делаете. Jens

Ваш Ответ

7   ответов
1
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();
                }
            }
        }
    }

}
Это хорошо сработало для меня Harry .Naeem
0

когда мне пришлось загружать что-то из базы данных перед входом пользователя в приложение, и я решил эту проблему.

ИспользоватьObservableInteger ты можешь это сделат

сначала объявить об этом

private ObservableInteger mObsInt;

затем в вашем onCreate у вас будет прослушиватель, ожидающий изменения значений mObsInt, после изменения этих значений вы можете делать все, что захотите

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

Так, как это работает

ObservableInteger будет искать изменения в переменнойmObsInt, так скажем, еслиmObsInt равно 1, он будет делать что-то, если равен 2, будет делать что-то другое, поэтому, чтобы решить эту проблему с 2asynctasks легко, когда один изasynctasks заканчиваетmObsInt будет равно 1, если другойasyncTask заканчивается такmObsInt будетmObsInt++, а потом твойmObsInt будет равно 2, слушатель будет ждать значений, а затем делать то, что вы хотите сделать, когда значения соответствуют вашему if if в onCreate метод

сейчас, просто в ваших асинхронных задачах просто вставьте в метод onPostExecute () эту строку

mObsInt.set(mObsInt.get()+1);

так, если первый асинхронный финиш завершается, mObsint == 1, если второй финиш mObsInt == 2, а затем вы обрабатываете то, что хотите сделать, в своем методе onCreate

надеюсь, это поможет вам, это помогло мне

Вы можете получить больше информации в этом документе:https: //developer.android.com/reference/android/databinding/ObservableInt.htm

счастливое кодирование!

4

чтобы вкладывать AsyncTask. Сделайте всю тяжелую работу в DoInBackground и просто опубликовать / обновить результаты. Другими словами, объедините обработку второго AsyncTask с вашим первым.

ЕгоdoInBackground содержит// call the rest api комментарий. результат этого вызова, по-видимому,JSONObject анализируется и отправляется на следующий шаг - что в его случае является еще однимAsyncTask. Jens
Честно говоря, это, очевидно, то, что он делает. Jens
depends - поведение для AsyncTask: s было немного изменено для ICS, что делало их последовательными по умолчанию - то есть одна долго выполняемая задача блокировала бы другие, пока она не будет завершена. Jens
что вы имеете в виду waqaslam
он не должен передавать результат в другую задачу. Он может просто обработать это в той же задаче. не может ли он? waqaslam
21

1:

Вы можете написать код для authTask, а затем для imageTask, один за другим, в пределах одногоdoInBackground(). Этот единственный экземпляр AsyncTask будет запущен однимexecute() заявление. Это может или не может быть практичным в зависимости от необходимых взаимодействий пользовательского интерфейса.

2:

Редактировать: как отметил Кабуку, эта информация в основном для HoneyComb +. Предварительно HoneyComb я бы точно выбрал с опцией1 над.executeOnExecutor () это уровень API 11 +

В последних версиях,execute() по умолчанию отправляет ваши AsyncTasks (ICS +). Если вы хотите убедиться, что это произойдет, укажите серийного исполнителя.

В твоем случае это будет:

authTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
// Image task will only be done AFTER textViewTask is done
imageTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);

А для более новых версий просто

...
// ICS+ and pre honeycomb (I think)
authTask.execute();
// Image task will only be done AFTER textViewTask is done
imageTask.execute();
...

От Документация AsycnTask.execute ():

Примечание: эта функция планирует задачу в очереди для одного фонового потока или пула потоков в зависимости от версии платформы. При первом представлении AsyncTasks выполнялись последовательно в одном фоновом потоке. Начиная с DONUT, это было изменено на пул потоков, позволяющий нескольким задачам работать параллельно. После HONEYCOMB планируется изменить это обратно на один поток, чтобы избежать распространенных ошибок приложения, вызванных параллельным выполнением.

PS: чтобы запускать задачи независимо друг от друга, вы должны использоватьAsyncTask.THREAD_POOL_EXECUTOR. Это требует другого исполнителя:

// Go parallel! (NOT what you want)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@ hcpeter - Хмм ... похоже, executeOnExecutor - это API-уровень 11. Вам просто нужно связать их в цепочку либо в том же doInbackground, либо вызвать один из другого onPostExecute (как вы уже делаете). Peter Ajtai
Все это хорошая информация. К сожалению, если вы хотите поддерживать pre-HC / ICS, вы не можете этого сделать. 1. Задачи не выполняются последовательно в этих версиях. 2. API для указания исполнителя еще не введены. В 1.6 AsyncTask использовала пул потоков размером 1, но после этого это был размер основного пула 5. Единственное решение - сделать что-то похожее на OP, если вам нужно поддерживать более старые версии. kabuko
Ваш ответ объяснил мне, почему в новых версиях API мои задачи отказываются работать параллельно. Кажется, мне не хватало THREAD_POOL_EXECUTOR! Ilya Kogan
Привет, было бы здорово, но я должен использовать API уровня 10. Можно ли выполнить какое-то задание подряд? hcpeter
@ kabuko - спасибо, я заметил это в ответе. Peter Ajtai
26

вы можете использоватьgetStatus() проверяет, является лиAsyncTask находится в состоянии ожидания, выполняется или завершено. и когда finsh запустит новое задание. like

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
}

пример для вашего приложения:

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
        }
      }
   }); 
да, прямо в вашем случае этот пост может помочь вам / Stackoverflow.com вопросы / 8337419 / ... помни об этой ситуации. ρяσѕρєя K
Извините за поздний ответ, я заболела. У меня есть одна проблема с этим решением: в authTask я получаю данные, которые являются параметром для imageTask. Почему-то мне нужно знать, что authTask завершен, и я могу запустить imageTask .. hcpeter
Это не проблема, просто возьмите и сохраните где-нибудь параметр из onPostExecute authTask, а когда authTask закончит, передайте его imageTask ρяσѕρєя K
Позвольте мне попробовать это решение, спасибо за пример! Таким образом, я могу запустить 2 отдельные задачи подряд, и когда authTask закончится, я смогу пройти через пользователя. hcpeter
Спасибо, наконец, я использую этот подход и немного реструктурирую свое приложение hcpeter
1

который вы показали, нет смысла создавать вторую задачу. Просто получите свое изображение внутриdoInBackground первого задания сразу после авторизации. Если вам нужно обновить интерфейс между ними, вы можете сделать это в процессе обновления.

0

У меня есть идея сделать асинхронную серию только в одной асинхронной задаче:

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;
            }

А в своей основной ветке просто вызовите асинхронную задачу следующим образом:

ShowMyProgress(); //if you like
new MyAsyncTask().execute("taskA");

И, наконец, вы можете скрыть свой прогресс на onPostExecute, например:

protected void onPostExecute(final Boolean success) {
        if (success) {
            ....

            HideMyProgress();
        }
}

Похожие вопросы