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: On m'a demandé il y a longtemps que je n'étais pas familier avec Java, maintenant que je suis mieux avec, je vais faire un bref résumé:
Le point essentiel de la tâche asynchrone est que la tâche est asynchronous
, ce qui signifie qu'après avoir appelé execute()
sur la tâche, la tâche commence à s'exécuter sur un thread propre. renvoyer une valeur depuis asynctask serait inutile car le thread appelant d'origine a déjà effectué d'autres tâches (la tâche est donc asynchrone).
Pensez au temps: à un moment donné, vous avez lancé une tâche qui s'exécutera en parallèle avec le thread principal. Lorsque la tâche d'exécution parallèle s'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 renvoyer une valeur au thread principal.
Je venais de C alors je ne savais pas grand chose à ce sujet. Mais il semble que beaucoup de gens ont la même question, alors j'ai pensé éclaircir un peu.
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;
}
}
C’est ce que onPostExecute()
est pour. Il fonctionne sur le fil de l'interface utilisateur et vous pouvez envoyer votre résultat à partir de cet écran (ou de tout autre endroit dont vous avez besoin). Il ne sera appelé que lorsque le résultat final sera disponible. Si vous voulez obtenir des résultats intermédiaires, jetez un œil à onProgressUpdate()
Le moyen le plus simple est de passer l'objet appelant dans la tâche asynchrone (lors de sa construction si vous le souhaitez):
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 dans la classe appelante (votre activité ou votre fragment), exécutez la tâche:
public class MyImagesPagerFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
AsyncGetUserImagesTask mGetImagesTask = new AsyncGetUserImagesTask(this);
mGetImagesTask.execute();
}
Et ensuite onPostExecuteMethod appellera n'importe quelle méthode de votre classe d'origine que vous aimez, par exemple:
public void updateAdapter(List<ImageData> images) {
mImageAdapter.setImages(images);
mImageAdapter.notifyDataSetChanged();
}
}
Exemple de code: Activity utilise AsyncTask pour obtenir une valeur dans un thread en arrière-plan, puis AsyncTask renvoie le résultat à Activity 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);
}
}
}
vous pouvez essayer celui-ci: myvalue = new myTask().execute().get();
moins il gèlera le processus jusqu'à ce que l'asyncron ne soit pas terminé;
Vous devez utiliser des "protocoles" pour déléguer ou fournir des données à la AsynTask
.
Délégués et sources de données
Un délégué est un objet qui agit pour le compte d'un autre objet ou en coordination avec celui-ci lorsque cet objet rencontre un événement dans un programme. ( définition Apple )
Les protocoles sont des interfaces qui définissent certaines méthodes pour déléguer certains comportements.
DELEGATE: Capturer 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 délégué dans doInBackground, et que le délégué tente de modifier une vue, celle-ci plantera, car celle-ci ne peut être manipulée que par le thread principal.
EXTRA
DATASOURCE: Fournit des données à l'objet dans le fil de l'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();
}
}
AsyncTask<Params, Progress, Result>
Params
- type de données en entrée de la tâcheProgress
- comment informer le monde du progrèsResult
- type de données de sortie de la tâchePense comme
Result = task(Params)
Charger YourObject
par l'URL de la chaîne:
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/");
Pour vous obtenir le résultat d'un AsyncTask il doit le faire après le super.onPostExcecute(result)
; Parce que cela signifie que l’arrière-plan et la tâche Async sont également terminés. 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 méthode checkResponseForIntent pourrait ressembler à 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 ProgressBar ne fonctionne tout simplement pas avec get()
, en fait, il ne fonctionne que lorsque doInBackground se termine.
J'espère que ça vous aide.
Passez la classe MainActivity à Async, vous aurez ainsi accès 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);
}
}