Данные должны быть возвращены из другого метода, чем тот, которому параллельный поток возвращает - PullRequest
0 голосов
/ 23 марта 2012


У меня есть класс, который расширяет AsyncTask.
В методе doInBackground () я подключаюсь к серверу и получаю данные.
В указанном классе есть метод get (), который возвращает эти данные пользователю.
Поэтому я вызываю метод execute () в этом классе и вскоре после этого возвращаю переменную-член «response».
Но возвращается значение null, поскольку соединение еще не установлено.
Итак, я установил переменную response в onPostExecute () и хочу вернуться к основному потоку отсюда.
Как мне это сделать, не используя такой цикл:

while(! gotResponse) continue;

Мой псевдокод:

//Main thread
class blah {
   .... onCreate(..) {
      ConHelper ch = new ConHelper();
      String data = ch.get();
   }
}
class ConHelper extends AsyncTask<...>{
   private String response;
   private boolean gotResponse;

   ... get() {
      this.execute(...);
      while(! this.gotResponse) continue;
      return this.response;
   }
   ... doInBackground(..) {
      // connect and get data.
   }
   ... on postExecute(...) {
      //set response and gotResponse from obtained data.
   }

Ответы [ 3 ]

2 голосов
/ 23 марта 2012

Концепция AsyncTask заключается в том, что сама задача инициирует все, что необходимо сделать после получения результатов. Метод типа get() не может быть реализован. Конечно, не пытайтесь ждать в основном потоке (UI), пока результаты не станут доступны. (Кстати, AsyncTask уже определяет метод get() для извлечения результатов. Если результаты недоступны, они будут блокироваться, пока они не будут. Не вызывать его из потока пользовательского интерфейса.)

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

Напишите свою логику пользовательского интерфейса (onCreate() и т. Д.), Чтобы не приходилось ждать результатов, и чтобы она работала, когда результаты еще не доступны. (Так, например, вы можете отобразить пустое поле или сообщение «Пожалуйста, подождите», где вы хотите отобразить data. Или вы можете открыть «рабочее» диалоговое окно с предупреждением и удалить его из onPostExecute().)

1 голос
/ 23 марта 2012

Ted Hopp ответит то, что вы ищете. Я добавляю этот ответ, чтобы опубликовать код. Как и предполагал Тед, ваша активность должна просто заниматься своим делом, пока AsyncTask делает свое дело.

Когда ConHelper выполнено, он может получить доступ к Activity через onPostExecute, который запускает в главном потоке .

Вы, конечно, не хотите вызывать get on из onCreate, потому что цикл while в get просто вызовет блокировку основного потока, уничтожив всю причину создания ConHelper во-первых.

Ключ в том, что вы хотите структурировать Activity так, чтобы он мог работать без доступа к каким-либо данным, полученным в ConHelper. Если вы не можете продолжить работу без переменной data из вашего примера onCreate, то перенос работы из основного потока вам не поможет.

Итак, давайте предположим, что вы хотите выполнить длительный вызов, который возвращает String, который вы хотели бы отобразить в TextView. Вот один из способов сделать это:

public class MyActivity extends Activity {
   protected TextView myTextView;


   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main); // or whatever layout you have
      myTextView = (TextView)findViewById(R.id.mytextview); //or whatever widgets/ids you use
      ConHelper ch = new ConHelper();
      ch.execute();
   }

   class ConHelper extends AsyncTask<..., Void, String>{

      protected String doInBackground(..) {
        // connect and get data.
        return <some lengthy method call that returns a String>;
      }
      protected void onPostExecute(String resultFromDoInBackground) {
        myTextView.setText(resultFromDoInBackground);
      }
   }
}
1 голос
/ 23 марта 2012

Я не уверен, что есть способ сделать это в платформе Android. Если вы беспокоитесь о вращении, вы можете сделать что-то вроде:

final Object lock = new Object();

// wait until the value has been set
synchronized (lock) {
    // we do a while loop to protect against interrupts and race conditions
    while(response == null) {
        try {
            lock.wait();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return;
        }
    }
}

Затем, когда вы будете готовы установить ответ, вы сделаете:

synchronized (lock) {
    response = ...;
    lock.notifyAll();
}
...