Возвращает значение из AsyncTask в Android [дубликат]

этот вопрос уже есть ответ здесь:

один простой вопрос: Можно ли вернуть значение в AsyncTask?

//AsyncTask is a member class
private class MyTask extends AsyncTask<Void, Void, Void>{

    protected Void doInBackground(Void... params) {
         //do stuff
         return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        //do stuff
        //how to return a value to the calling method?
    }
}

а потом в моей Activity/Fragment:

// The task is started from activity
myTask.execute()
// something like this?
myvalue = myTask.getvalue() 

изменить: Это было задано давно, где я не был знаком с Java, теперь, когда я лучше с ним, я сделаю краткое резюме:

точка асинхронной задачи заключается в том, что задача asynchronous, это означает, что после вызова execute() в задаче задача запускается в собственном потоке. возврат значения из asynctask будет бессмысленным, потому что исходный вызывающий поток уже продолжал делать другие вещи (таким образом, задача асинхронная).

думать о времени: В какой-то момент Вы запустили задачу, которая будет выполняться параллельно с основным потоком. Когда параллельно выполняемая задача завершена, время также истекло в основном потоке. Параллельная задача не может вернуться в прошлое, чтобы вернуть значение в основной поток.

Я шел от C, поэтому я мало знал об этом. Но, похоже, у многих людей один и тот же вопрос, поэтому я подумал, что немного проясню его.

9 ответов


почему бы не вызвать метод, который обрабатывает значение?

public class MyClass extends Activity {

    private class myTask extends AsyncTask<Void, Void, Void> {

        //initiate vars
        public myTask() {
            super();
            //my params here
        }

        protected Void doInBackground(Void... params) {
            //do stuff
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            //do stuff
            myMethod(myValue);
        }
    }

    private myHandledValueType myMethod(Value myValue) {
        //handle value 
        return myHandledValueType;
    }
}

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


самый простой способ-передать вызывающий объект в асинхронную задачу (при ее создании, Если хотите):

public class AsyncGetUserImagesTask extends AsyncTask<Void, Void, Void> {

    private MyImagesPagerFragment mimagesPagerFragment;
    private ArrayList<ImageData> mImages = new ArrayList<ImageData>();

    public AsyncGetUserImagesTask(MyImagesPagerFragment imagesPagerFragment) {
        this.mimagesPagerFragment = imagesPagerFragment;
    }

    @Override
    public Void doInBackground(Void... records) {
        // do work here
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mimagesPagerFragment.updateAdapter(mImages);
    }
}

и в вызывающем классе (ваша активность или фрагмент) выполните задачу:

public class MyImagesPagerFragment extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        AsyncGetUserImagesTask mGetImagesTask = new AsyncGetUserImagesTask(this);
        mGetImagesTask.execute();
    }

и тогда onPostExecuteMethod вызовет любой метод в вашем исходном классе, например:

    public void updateAdapter(List<ImageData> images) {
        mImageAdapter.setImages(images);
        mImageAdapter.notifyDataSetChanged();
    }
}

вы можете попробовать это: myvalue = new myTask().execute().get(); минус в том, что он заморозит процесс, пока asyncron не будет завершен;


пример кода: Activity использует AsyncTask для получения значения в фоновом потоке, затем AsyncTask возвращает результат обратно в Activity, вызывая processValue:

public class MyClass extends Activity {
  private void getValue() {
      new MyTask().execute();
  }

  void processValue(Value myValue) {
     //handle value 
     //Update GUI, show toast, etc..
  }

  private class MyTask extends AsyncTask<Void, Void, Value> {
    @Override
    protected Value doInBackground(Void... params) {
      //do stuff and return the value you want 
      return Value;
    }

    @Override
    protected void onPostExecute(Value result) {
      // Call activity method with results
      processValue(result);
    }
  }
}

вам нужно использовать "протоколы" делегировать или предоставлять информацию AsynTask.

делегаты и источники данных

делегат-это объект, который действует от имени, или в координации с другим объектом, когда этот объект обнаруживает событие в программе. (определение Apple)

протоколы-это интерфейсы, которые определяют некоторые методы для делегирования некоторых поведения.


делегат: событий Capturate от объекта в фоновом потоке


AsynkTask:

public final class TaskWithDelegate extends AsyncTask<..., ..., ...> {
    //declare a delegate with type of protocol declared in this task
    private TaskDelegate delegate;

    //here is the task protocol to can delegate on other object
    public interface TaskDelegate {
        //define you method headers to override
        void onTaskEndWithResult(int success);
        void onTaskFinishGettingData(Data result);
    }

    @Override
    protected Integer doInBackground(Object... params) {
        //do something in background and get result
        if (delegate != null) {
            //return result to activity
            delegate.onTaskFinishGettingData(result);
        }   
    }

    @Override
    protected void onPostExecute(Integer result) {
        if (delegate != null) {
            //return success or fail to activity
            delegate.onTaskEndWithResult(result);
        }   
    }
}

действие:

public class DelegateActivity extends Activity implements TaskDelegate {
    void callTask () {
            TaskWithDelegate task = new TaskWithDelegate;
        //set the delegate of the task as this activity
        task.setDelegate(this);
    }

    //handle success or fail to show an alert...
    @Override
    void onTaskEndWithResult(int success) {

    }

    //handle data to show them in activity...
    @Override
    void onTaskFinishGettingData(Data result) {

    }
}

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


дополнительно

источник: предоставить данные объекту в фоновом потоке


AsyncTask:

public final class TaskWithDataSource extends AsyncTask<..., ..., ...> {
    //declare a datasource with type of protocol declared in this task
    private TaskDataSource dataSource;
    private Object data;

    //here is the task protocol to can provide data from other object
    public interface TaskDataSource {
        //define you method headers to override
        int indexOfObject(Object object);
        Object objectAtIndex(int index);
    }

    @Override
    protected void onPreExecute(Integer result) {
        if (dataSource != null) {
            //ask for some data
            this.data = dataSource.objectAtIndex(0);
        }   
    }

    @Override
    protected Integer doInBackground(Object... params) {
        //do something in background and get result
        int index;
        if (dataSource != null) {
            //ask for something more
            index = dataSource.indexOfObject(this.data);
        }   
    }
}

действие:

public class DataSourceActivity extends Activity implements TaskDataSource {
    void callTask () {
            TaskWithDataSource task = new TaskWithDataSource;
        //set the datasource of the task as this activity
        task.setDataSource(this);
    }

    //send some data to the async task when it is needed...
    @Override
    Object objectAtIndex(int index) {
        return new Data(index);
    }

    //send more information...
    @Override
    int indexOfObject(Object object) {
        return new object.getIndex();
    }
}

общие параметры

AsyncTask<Params, Progress, Result>
  • Params - тип входных данных задачи
  • Progress - как информировать мир о прогрессе
  • Result - тип выходных данных задачи

думать

Result = task(Params)

пример

загрузить YourObject по строке URL:

new AsyncTask<String, Void, YourObject>()
{
    @Override
    protected void onPreExecute()
    {
        /* Called before task execution; from UI thread, so you can access your widgets */

        // Optionally do some stuff like showing progress bar
    };

    @Override
    protected YourObject doInBackground(String... url)
    {
        /* Called from background thread, so you're NOT allowed to interact with UI */

        // Perform heavy task to get YourObject by string
        // Stay clear & functional, just convert input to output and return it
        YourObject result = callTheServer(url);
        return result;
    }

    @Override
    protected void onPostExecute(YourObject result)
    {
        /* Called once task is done; from UI thread, so you can access your widgets */

        // Process result as you like
    }
}.execute("http://www.example.com/");

для вас получить результат от AsyncTask это нужно сделать после super.onPostExcecute(result); Потому что это означает, что фон и AsyncTask также закончились. например:

... into your async task

@Override
protected void onPostExecute(MyBeanResult result) {
    if (dialog.isShowing()) {
        dialog.dismiss();
    }
    if (mWakeLock.isHeld()) {
        mWakeLock.release();
    }
    super.onPostExecute(result);
    MyClassName.this.checkResponseForIntent(result);
}

и methodr checkResponseForIntent может быть чем-то вроде этого:

private void checkResponseForIntent(MyBeanResult response) {
    if (response == null || response.fault != null) {
        noServiceAvailable();
        return;
    }
 ... or do what ever you want, even call an other async task...

у меня была эта проблема с использованием .get() С AsyncTask и ProgressBar просто не работает с get() на самом деле, это работает только один раз, что doInBackground заканчивает.

Я надеюсь, что это поможет вам.


передайте MainActivity в класс Async, чтобы получить доступ к функциям MainActivity во внутреннем классе, Это прекрасно работает для меня:

public class MainActivity extends ActionBarActivity {

   void callAsync()
   {
      Async as = new Async(this,12,"Test");
      as.execute();
   }

   public void ReturnThreadResult(YourObject result)
   {
     // TO DO:
     // print(result.toString());

   }
}


public class Async extends AsyncTask<String, String, Boolean> {
    MainActivity parent;
    int param1;
    String param2;

    public Async(MainActivity parent,int param1,String param2){
       this.parent = parent;
       this.param1 = param1;
       this.param2 = param2;
    }

    @Override
    protected void onPreExecute(){};

    @Override
    protected YourObject doInBackground(String... url)
    {
        return result;
    }

    @Override
    protected void onPostExecute(YourObject result)
    {
       // call an external function as a result 
       parent.ReturnThreadResult(result);
    }
  }