Return a value from AsyncTask in Android

One simple question: is it possible to return a value in 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?
}
}

And then within my Activity/Fragment:

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

EDIT: This was asked a long time ago where I wasn't familiar with Java, now that I'm better with it, I 'll do a quick summary:

The point of async task is that the task is asynchronous, meaning that after you call execute() on the task, the task starts running on a thread of its own. returning a value from asynctask would be pointless because the original calling thread has already carried on doing other stuff (thus the task is asynchronous).

Think of time: At one point of time, you started a task that will run in parallel with the main thread. When the parallel-running task completed, time has also elapsed on the main thread. The parallel task cannot go back in time to return a value to the main thread.

I was coming from C so I didn't know much about this. But it seems that lots of people are having the same question so I thought I would clear it up a bit.

209809 次浏览

这就是 onPostExecute()的作用。它在 UI 线程上运行,您可以将结果从那里传递到屏幕(或者您需要的任何其他地方)。在最终结果可用之前不会调用它。如果您想交付中间结果,请看一下 onProgressUpdate()

为什么不调用处理该值的方法?

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

For you get the result from a AsyncTask it needs to do it after the 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);
}

方法 checkResponseForInant 可能是这样的:

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...

我在使用来自 AsyncTask.get()时遇到了这个问题,而 ProgressBar 在使用 get()时根本无法工作,实际上,它只能工作一次。

I hope that it helps you.

你可以试试这个: myvalue = new myTask().execute().get(); 负的是它将冻结进程,直到异步不能完成;

最简单的方法是将调用对象传递给异步任务(如果愿意,可以在构造它时) :

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

代码示例: Activity 使用 AsyncTask 获取后台线程中的值,然后 AsyncTask 通过调用 processValue 将结果返回 Activity:

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委托或提供数据。

Delegates and Data Sources

委托是当另一个对象在程序中遇到事件时代表该对象或与该对象协调行事的对象。(苹果的定义)

protocols are interfaces that define some methods to delegate some behaviors.


代理: 捕获来自后台线程中对象的事件


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) {


}
}

编辑: 如果您在 doInBack 中调用 committee,并且该委托尝试编辑某个视图,那么该视图将崩溃,因为视图只能由主线程操作。


// this refers to Activity
this.runOnUiThread(new Runnable() {
@Override
public void run() {
// Here you can edit views when task notify some changes from background thread
textView.setText(someValue);
}
});

额外的

DATASOURCE: 为后台线程中的对象提供数据


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>
  • 任务的输入数据类型
  • 如何向世界宣传进步
  • Result — task's output data type

想像一下

Result = task(Params)

Example

通过字符串加载 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/");

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