ProgressDialog не отображается, когда AsyncTask.get () называется [дубликат]

17

Я хочу показать progressDialog при извлечении JSON с любого сервера. Поэтому я использовал AsyncTask в качестве решения (не уверен в другом выходе).

Все в порядке, ProgressDialog работает правильно, пока я не вызову метод .get (), используя экземпляр AsyncTask. Я предполагаю, что это как-то блокирует пользовательский интерфейс. Вот мой AsyncTask:

public class myAsync extends AsyncTask<String, String, List> {

    String message; // for dialog message
    ProgressDialog progress; 
    Intent myIntent;
    Context ctx;

    public myAsync(String message, Context ctx) {
        this.message = message;
        this.ctx = ctx;
        progress = new ProgressDialog(ctx);
    }

    @Override
    protected void onPreExecute() { 
        progress.setMessage(message);
        progress.setIndeterminate(true);
        progress.setCancelable(false);
        progress.show();    
    }

    @Override
    protected List doInBackground(String... params) {
        //returns any list after the task
        return anyList; 
    }

    @Override
    protected void onPostExecute(List result) {
        if(progress.isShowing())
            progress.dismiss();
    }
}

И вот myActivity, который вызывает AsyncTask:

myAsync asyncTask = new myAsync("Loading...", this);
asyncTask.execute("Any string", "Other string");
asyncTask.get(); // If I comment out this line, ProgressDialog works

После выполнения, когда я попытался записать результат из doInBackground и onPostExecute, проблема не возникает. Но если я хочу получить с .get () результат, ProgressDialog не отображается или показывается так мало времени (может быть, 0,2 секунды)

В чем проблема?     

задан Ogulcan Orhan 26.01.2012 в 15:04
источник
  • вы лишаете каких-либо исключений? –  Richie 26.01.2012 в 15:11
  • Не совсем. Как я уже сказал, диалоговое окно можно увидеть так мало времени. Действительно, это должно быть видно как минимум на 2 секунды. –  Ogulcan Orhan 26.01.2012 в 15:14

4 ответа

23

Да, get() ждет , если это необходимо для завершения вычисления, а затем извлекает его результат. Это означает, что вы блокируете свой поток пользовательского интерфейса, ожидая результата.

Решение: не вызывайте get

Обычно вы вызываете функцию (обратный вызов) в postExecute .

    
ответ дан rds 26.01.2012 в 15:24
источник
  • См. stackoverflow.com/questions/3291490/... для примера реализации –  rds 26.01.2012 в 15:29
  • Получил! Спасибо за образец, решили это, но все еще есть проблемы для разных предметов. –  Ogulcan Orhan 26.01.2012 в 16:06
  • , но если я хочу использовать возвращаемое значение AsyncTask и на основе возвращаемого значения i wannt для вызова нового URL-адреса, что я могу сделать для этого? я думаю, таким образом мы должны использовать .get без него, если есть какой-либо вариант, тогда PLS помочь мне –  PankajAndroid 23.05.2013 в 12:57
  • Еще один способ: если ваш код выполняется в потоке пользовательского интерфейса, оберните свой AsyncTask новым потоком ... ex) new Thread (новый Runnable () {.... result = yourAsyncTask.execute (). get () ;. ....}).Начало(); –  Wonho Jung 10.01.2018 в 07:23
15

Вызов .get() изменяет ваш AsyncTask на эффективный " SyncTask ", поскольку он вызывает текущий поток (который будет потоком пользовательского интерфейса) до тех пор, пока AsyncTask не завершит свою обработку. Поскольку теперь вы блокируете поток пользовательского интерфейса, вызов метода ProgressDialog .show() никогда не дает возможности диалоговому экрану сделать сам экран.

Удаление вызова позволит ему правильно работать в фоновом режиме.

Если вам нужно выполнить обработку после завершения задачи, я предлагаю вам либо поместить ее внутри самого метода onPostExecute , либо использовать обратный вызов для Activity из onPostExecute .

    
ответ дан Jake Wharton 26.01.2012 в 15:23
источник
  • Я думаю, вы правы, но можете ли вы объяснить это больше? Любые фрагменты. Потому что я не уверен, как использовать обратный вызов из onPostExecute. Благодарю. –  Ogulcan Orhan 26.01.2012 в 15:36
4

Если я правильно понял ваш вопрос, вам нужно обновить ход вашей AsyncTask в ProgressDialog , и это не работает в настоящее время. Итак, несколько замечаний: я не уверен, чего вы пытаетесь достичь с помощью .get() , но я предполагаю, что вы хотите отобразить прогресс.

Я изменил вашу программу ниже, чтобы обновить поток пользовательского интерфейса с помощью прогресса AsyncTask. Каждый раз, когда вам нужно обновить прогресс, обновите переменную prog в методе doInBackground .

public class myAsync extends AsyncTask<String, Integer, List> {

  String message; // for dialog message
  ProgressDialog progress; 
  Intent myIntent;
  Context ctx;

  public myAsync(String message, Context ctx) {
    this.message = message;
    this.ctx = ctx;
    progress = new ProgressDialog(ctx);
  }

  @Override
  protected void onPreExecute() { 
    // Runs on the UI thread
    progress.setMessage(message);
    progress.setIndeterminate(true);
    progress.setCancelable(false);
    progress.show();    
  }

  @Override
  protected List doInBackground(String... params) {
    // Runs in the background thread
    // publish your progress here!!
    int prog = 5; // This number will represent your "progress"
    publishProgress(prog);
    return anyList; 
  }


  protected void onProgressUpdate(Integer... progress) {
    // Runs in the UI thread
    // This method will fire (on the UI thread) EVERYTIME publishProgress
    // is called.
    Log.d(TAG, "Progress is: " +progress);
  }

  @Override
  protected void onPostExecute(List result) {
    // Runs in the UI thread

    for (int i=0; i<result.size(); i++) {
      Log.d(TAG, "List item: " + result.get(i));
    }

    if(progress.isShowing())
      progress.dismiss();
  }
}
    
ответ дан Marvin Pinto 26.01.2012 в 15:16
источник
  • С get, он, очевидно, хочет получить результат от задачи, чтобы обновить свой интерфейс –  rds 26.01.2012 в 15:30
  • @rds Вы бы использовали .get в контексте AsyncTask? Поэтому почему мое предположение «Я не уверен, чего вы пытаетесь достичь с помощью ...», а затем на мою интерпретацию вопроса OP. –  Marvin Pinto 26.01.2012 в 15:34
  • @Marvin, во-первых, спасибо за ваш комментарий. Просто, я получаю json с веб-сервера. Выполняя эту транзакцию, просто хочу показать progressdialog-окна, вот и все. Если я не позвоню .get (), все в порядке. Диалог отображается, как только нажимается кнопка (кнопка запускается асинхронно). Но, кстати, мне тоже нужен результат json. Как я знаю, метод .get () возвращает результат. Когда я попытался получить, диалоговое окно отображается так мало времени во время транзакции. Надеюсь, теперь это проще. –  Ogulcan Orhan 26.01.2012 в 15:35
  • @OgulcanOrhan Попробуйте предложения других отправителей, и если вы все еще застряли, я могу попытаться помочь вам. –  Marvin Pinto 26.01.2012 в 15:39
  • @OgulcanOrhan Я сделал небольшое редактирование метода onPostExecute моего ответа, чтобы продемонстрировать, как обрабатывать элементы в вашем списке в потоке пользовательского интерфейса. Поэтому, если вам нужно, например, обновить ListView, вы сделаете это в методе onPostExecute. Это то, что я предполагаю, что вы пытаетесь сделать. т. е. после того, как это сделано, получите и сделайте что-нибудь с вашими результатами. Ну, сделайте что-то, что вы хотите поместить в метод onPostExecute. –  Marvin Pinto 26.01.2012 в 15:59
-2

Попробуйте использовать runOnUiThread следующим образом:

         runOnUiThread(new Runnable(){
            public void run() {
                dialog.show();
                }});    

Запуск чего-то в AsyncTask означает, что он убегает от UIthread, поэтому обычно вы не можете запускать операции ui изнутри методов Async без обработчиков и т. д., от которых я обычно не веду себя. Я также обрабатываю такое решение, создавая progressDialog как переменную в моем классе выше моего oncreate, чтобы он был видимым для всего класса. Затем я вызываю progressdialog прямо перед моей асинхромой, а затем, поскольку его видимый для всего класса я вызываю .dissmiss () в onPostExecute

    
ответ дан James andresakis 26.01.2012 в 15:12
источник
  • Оба параметра onPreExecute и onPostExecute запускаются в потоке пользовательского интерфейса. doInBackground - единственное, чего нет. –  Jake Wharton 26.01.2012 в 15:17
  • @JakeWharton Я думаю, что они только возвращают данные в поток пользовательского интерфейса и не работают на нем, но я могу ошибаться ..... Я точно не имею документацию по android, запомнив строку для строки, но lol –  James andresakis 26.01.2012 в 15:18
  • Я уже пробовал это, не работал. Спасибо, в любом случае. –  Ogulcan Orhan 26.01.2012 в 15:37