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

Возможный дубликат:
AsyncTask блокирует угрозу пользовательского интерфейса и показывает прогресс-бар с задержкой

Я хочу показать 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 секунды)

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

4 ответа

Решение

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

Решение: не звоните get

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

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

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

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

Если я правильно понимаю ваш вопрос, вам нужно обновить ход выполнения вашей 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();
  }
}

Попробуйте использовать runOnUiThread так:

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

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

Другие вопросы по тегам