Retourner une valeur D'AsyncTask dans Android [dupliquer]

cette question a déjà une réponse ici:

Une question simple: est-il possible de retourner une valeur dans 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?
    }
}

et puis dans mon Activity / Fragment :

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

EDIT: Cela a été demandé Il ya longtemps où je n'étais pas familier avec Java, maintenant que je suis mieux avec elle, je vais faire un résumé rapide:

le point de la tâche async est que la tâche est asynchronous , ce qui signifie qu'après que vous appelez execute() sur la tâche, la tâche commence à courir sur un fil de sa propre. retourner une valeur d'asynctask serait inutile parce que le thread d'appel original a déjà continué à faire d'autres choses (donc la tâche est asynchrone).

pensez au temps: À un moment donné du temps, vous avez commencé une tâche qui s'exécute en parallèle avec le thread principal. Lorsque la tâche d'exécution en parallèle est terminée, le temps s'est également écoulé sur le thread principal. La tâche parallèle ne peut pas remonter dans le temps pour retourner une valeur au thread principal.

je venais de C donc je ne savais pas grand chose à ce sujet. Mais il semble que beaucoup de gens ayant la même question alors j'ai pensé que je voudrais éclaircir un peu.

97
demandé sur tom91136 2012-02-27 03:19:31

9 réponses

pourquoi ne pas appeler une méthode qui gère la valeur?

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;
    }
}
30
répondu ababzy 2015-02-22 20:29:20

C'est à ça que sert onPostExecute() . Il s'exécute sur le thread de L'interface utilisateur et vous pouvez transmettre votre résultat de là à l'écran (ou n'importe où ailleurs dont vous avez besoin). Il ne sera pas appelé tant que le résultat final n'est pas disponible. Si vous souhaitez obtenir des résultats intermédiaires, jetez un coup d'oeil à onProgressUpdate()

39
répondu Ted Hopp 2012-02-26 23:22:31

la manière la plus simple est de passer l'objet appelant dans la tâche async (en le construisant si vous voulez):

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

et la classe d'appel (votre activité ou fragment) exécutent la tâche:

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

et ensuite la méthode onPostExecuteMethod appellera n'importe quelle méthode sur votre classe d'origine que vous aimez, par exemple:

    public void updateAdapter(List<ImageData> images) {
        mImageAdapter.setImages(images);
        mImageAdapter.notifyDataSetChanged();
    }
}
21
répondu Sheamus O'Halloran 2013-04-02 11:07:08

vous pouvez essayer celui-ci: myvalue = new myTask().execute().get(); moins il va geler le processus jusqu'à ce que asyncron ne sera pas terminé ;

9
répondu EugenUngurean 2013-08-24 11:07:21

exemple de Code: Activity utilise AsyncTask pour obtenir une valeur dans un thread de fond, alors AsyncTask renvoie le résultat à L'activité en appelant 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);
    }
  }
}
9
répondu jt-gilkeson 2018-09-07 10:21:14

vous devez utiliser " protocoles pour déléguer ou fournir des données au AsynTask .

délégués et sources de données

un délégué est un objet qui agit au nom ou en coordination avec un autre objet lorsque cet objet rencontre un événement dans un programme. ( Apple définition de )

Les protocoles

et sont des interfaces qui méthodes pour déléguer certains comportements.


délégué: capter les événements de l'objet dans le fil de fond


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

activité:

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: si vous appelez delegate dans doInBackground, et que le delegate essaye d'éditer une vue, que va s'écraser parce que la vue ne peut être manipulée que par le thread principal.


EXTRA

source de données: Fournir des données à l'objet dans le thread d'arrière-plan


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

activité:

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();
    }
}
8
répondu IgniteCoders 2018-04-26 15:31:35

utiliser des paramètres génériques

AsyncTask<Params, Progress, Result>
  • Params - type de données d'entrée de la tâche
  • Progress - comment informer le monde sur le progrès
  • Result - type de données de sortie de la tâche

Penser comme

Result = task(Params)

exemple

Charge YourObject par la chaîne de caractères de l'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/");
3
répondu Nikita Bosik 2018-02-27 07:09:51

Pour vous obtenez le résultat d'un AsyncTask il doit le faire après le super.onPostExcecute(result) ; Parce que cela signifie que le fond et L'AsyncTask ont aussi fini. par exemple:

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

et la methodr checkrespononseforintent pourrait par quelque chose comme ceci:

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

j'ai eu ce problème en utilisant .get() de AsyncTask et la barre de progression ne fonctionne tout simplement pas avec get() en fait, ça ne marche qu'une fois que doInBackground est fini.

j'espère que ça vous aidera.

3
répondu Klaus Villaca 2018-02-27 07:11:39

passez la MainActivity à la classe Async, vous accéderez ainsi aux fonctions MainActivity de la classe inner., Cela fonctionne très bien pour moi:

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);
    }
  }  
1
répondu Hamid 2016-06-18 21:51:30