Один простой вопрос: возможно ли вернуть значение в 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()
EDIT:
Это было задано давно, когда я не был знаком с Java, теперь, когда мне будет лучше, я сделаю краткое резюме:
Точка задачи async заключается в том, что задача asynchronous
, а это означает, что после вызова execute()
в задаче задача запускается в потоке. Возвращение значения из asynctask было бы бессмысленным, потому что исходный поток вызовов уже выполнял другие вещи (при этом задача была асинхронной).
Подумайте о времени:
В какой-то момент вы запустили задачу, которая будет работать параллельно с основным потоком. Когда выполнение параллельной задачи завершено, время также продолжается по основному потоку. Параллельная задача не может вернуться во времени, чтобы вернуть значение в основной поток.
Я приехал из C, поэтому я мало знал об этом. Но похоже, что у многих людей возникает один и тот же вопрос, поэтому я подумал, что немного проясню это.
Ответ 1
Почему бы не вызвать метод, который обрабатывает значение?
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;
}
}
Ответ 2
Что для onPostExecute()
. Он работает в потоке пользовательского интерфейса, и вы можете доставить свой результат оттуда на экран (или где-нибудь еще, что вам нужно). Он не будет вызываться до тех пор, пока окончательный результат не будет доступен. Если вы хотите предоставить промежуточные результаты, посмотрите onProgressUpdate()
Ответ 3
Самый простой способ - передать вызывающий объект в задачу async (при его построении, если хотите):
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();
}
}
Ответ 4
вы можете попробовать следующее: myvalue = new myTask().execute().get();
минус - это заморозит процесс до тех пор, пока асинхрон не будет закончен;
Ответ 5
Пример кода 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);
}
}
}
Ответ 6
Вам необходимо использовать "протоколы для делегирования или предоставления данных AsynTask
.
Делегаты и источники данных
Делегат - это объект, который действует от имени или в координации с другим объектом, когда этот объект встречает событие в программе. (Определение Apple)
протоколы - это интерфейсы, которые определяют некоторые методы делегирования некоторых действий.
DELEGATE: Захват событий из объекта в фоновом потоке
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...
void onTaskEndWithResult(int success) {
}
//handle data to show them in activity...
void onTaskFinishGettingData(Data result) {
}
}
РЕДАКТИРОВАТЬ:, если вы вызываете делегата в doInBackground, и делегат пытается отредактировать какое-то представление, которое будет сбой, потому что представление может управляться только основным потоком.
EXTRA
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...
Object objectAtIndex(int index) {
return new Data(index);
}
//send more information...
int indexOfObject(Object object) {
return new object.getIndex();
}
}
Ответ 7
Для получения результата от 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);
}
и метод 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.
Я надеюсь, что это поможет вам.
Ответ 8
Использовать общие параметры
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/");
Ответ 9
Передайте класс 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);
}
}