Devuelve un valor de AsyncTask en Android

Una pregunta simple: ¿es posible devolver un valor en 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? } } 

Y luego dentro de mi Activity / Fragment :

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

EDITAR: Esto fue preguntado hace mucho tiempo cuando no estaba familiarizado con Java, ahora que estoy mejor con él, haré un resumen rápido:

El objective de la tarea asincrónica es que la tarea es asynchronous , lo que significa que después de execute() en la tarea, la tarea comienza a ejecutarse en un hilo propio. devolver un valor de asynctask no tendría sentido porque el hilo de llamada original ya ha seguido haciendo otras cosas (por lo tanto, la tarea es asincrónica).

Piense en el tiempo: en un punto del tiempo, comenzó una tarea que se ejecutará en paralelo con el hilo principal. Cuando se completa la tarea de ejecución paralela, también ha transcurrido el tiempo en el hilo principal. La tarea paralela no puede retroceder en el tiempo para devolver un valor al hilo principal.

Venía de C, así que no sabía mucho sobre esto. Pero parece que mucha gente tiene la misma pregunta, así que pensé en aclararlo un poco.

¿Por qué no llamar a un método que maneja el valor?

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

Para eso es en onPostExecute() . Se ejecuta en el hilo de la interfaz de usuario y puede enviar su resultado desde allí a la pantalla (o en cualquier otro lugar que necesite). No se llamará hasta que el resultado final esté disponible. Si desea entregar resultados intermedios, eche un vistazo a onProgressUpdate()

La manera más fácil es pasar el objeto que llama a la tarea asíncrona (al construirlo si lo desea):

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

Y en la clase de llamada (su actividad o fragmento) ejecuta la tarea:

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

Y luego onPostExecuteMethod llamará a cualquier método en la clase de origen que desee, por ejemplo:

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

puedes probar este: myvalue = new myTask().execute().get(); menos, congelará el proceso hasta que asyncron no termine;

Ejemplo de código: la actividad usa AsyncTask para obtener un valor en una cadena de fondo, luego AsyncTask devuelve el resultado a la Actividad llamando a 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); } } } 

Necesita usar “protocolos” para delegar o proporcionar datos a AsynTask .

Delegados y fonts de datos

Un delegado es un objeto que actúa en nombre de, o en coordinación con, otro objeto cuando ese objeto encuentra un evento en un progtwig. ( Definición de Apple )

Los protocolos son interfaces que definen algunos métodos para delegar algunos comportamientos.


DELEGAR : Captura eventos del objeto en el hilo de fondo


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

Actividad:

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

EDITAR: si llama a delegar en doInBackground, y el delegado intenta editar alguna vista, se bloqueará porque la vista solo puede ser manipulada por el hilo principal.


EXTRA

DATASOURCE: proporciona datos al objeto en el hilo de fondo


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

Actividad:

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

Usa parámetros generics

 AsyncTask 
  • Params – tipo de datos de entrada de la tarea
  • Progress : cómo informar al mundo sobre el progreso
  • Result : tipo de datos de salida de la tarea

Piensa como

 Result = task(Params) 

Ejemplo

Cargue YourObject por cadena 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/"); 

Para obtener el resultado de una AsyncTask , debe hacerlo después del super.onPostExcecute(result) ; Porque esto significa que el fondo y AsyncTask también han terminado. p.ej:

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

y el método checkResponseForIntent podría decir algo como esto:

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

Tuve este problema al usar .get() de AsyncTask y ProgressBar simplemente no funciona con get() , en realidad, solo funciona una vez que doInBackground finaliza.

Espero que te ayude

Pase la clase MainActivity a Async, para que pueda acceder a las funciones MainActivity en la clase interna. Esto funciona bien para mí:

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