Возвращает значение из 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
.делегаты и источники данных
определение Яблока)протоколы-это интерфейсы, которые определяют некоторые методы для делегирования некоторых поведения.
делегат: захват событий из объекта в фоновом потоке
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); } }