Возвращает значение из AsyncTask в Android
Один простой вопрос: можно ли вернуть значение в AsyncTask
?
//AsyncTask is a member class private class MyTask extends AsyncTask{ 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, теперь, когда мне будет лучше, я сделаю краткое резюме:
- Возвращаемое значение из Thread
- тип возврата main в java
- Создать новый class из переменной в Java
- Android - Сохранить изображение с URL на SD-карту
- AES получает разные результаты в iOS (Obj-C) и Android (Java)
Точка async-задачи состоит в том, что задача является asynchronous
, а это означает, что после вызова функции execute()
в задаче задача запускается в streamе. Возrotation значения из asynctask было бы бессмысленным, потому что исходный stream вызовов уже выполнял другие вещи (при этом задача была асинхронной).
Подумайте о времени: в какой-то момент вы начали задачу, которая будет работать параллельно с основным streamом. Когда выполнение параллельной задачи завершено, время также продолжается по основному streamу. Параллельная задача не может вернуться во времени, чтобы вернуть значение в основной stream.
Я приехал с C, поэтому я мало что знал об этом. Но похоже, что у многих людей возникает один и тот же вопрос, поэтому я подумал, что немного разобрался.
- Что такое использование BaseColumns в Android?
- Получение параметров хеширования из запроса URL
- Дооснащение Ожидаемое BEGIN_OBJECT, но BEGIN_ARRAY
- Android Telegram App -> java.lang.UnsatisfiedLinkError: не реализована реализация для void
- Почему в Android не работает «System.out.println»?
- Включить частичную компиляцию в IntelliJ IDEA
- Отправляйте SMS до тех пор,
- размер растрового изображения превышает бюджетную ошибку Vm
Почему бы не вызвать метод, который обрабатывает значение?
public class MyClass extends Activity { private class myTask extends AsyncTask { //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()
. Он работает в streamе пользовательского интерфейса, и вы можете доставить свой результат оттуда на экран (или где-нибудь еще, что вам нужно). Он не будет вызываться до тех пор, пока окончательный результат не будет доступен. Если вы хотите предоставить промежуточные результаты, посмотрите на onProgressUpdate()
Самый простой способ – передать вызывающий объект в задачу async (при его построении, если хотите):
public class AsyncGetUserImagesTask extends AsyncTask { private MyImagesPagerFragment mimagesPagerFragment; private ArrayList mImages = new ArrayList (); 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); } }
И в вызывающем classе (ваша деятельность или fragment) выполняется задача:
public class MyImagesPagerFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { AsyncGetUserImagesTask mGetImagesTask = new AsyncGetUserImagesTask(this); mGetImagesTask.execute(); }
И тогда onPostExecuteMethod вызовет любой метод в вашем исходном classе, который вам нравится, например:
public void updateAdapter(List images) { mImageAdapter.setImages(images); mImageAdapter.notifyDataSetChanged(); } }
вы можете попробовать это: myvalue = new myTask().execute().get();
минус, это заморозит процесс до тех пор, пока асинхрон не будет закончен;
Пример кода: Activity использует AsyncTask для получения значения в фоновом streamе, затем 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 { @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 )
протоколы – это интерфейсы, которые определяют некоторые методы делегирования некоторых действий.
DELEGATE : вырезать события из объекта в фоновом streamе
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, и делегат попытается отредактировать какое-то представление, это приведет к сбою, потому что представление может управляться только основным streamом.
EXTRA
DATASOURCE: предоставление данных объекту в фоновом streamе
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(Params)
пример
Загрузите свой YourObject
помощью строки URL:
new AsyncTask() { @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); }
и метод 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()
, на самом деле, он работает только после завершения makeInBackground.
Надеюсь, это поможет вам.
Передайте MainActivity classу Async, поэтому вы получите доступ к функциям MainActivity во внутреннем classе. Это отлично работает для меня:
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 { 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); } }