web-dev-qa-db-fra.com

Comment obtenir le résultat de OnPostExecute () en activité principale car AsyncTask est une classe séparée?

J'ai ces deux classes. Mon activité principale et celle qui étend la AsyncTask, maintenant, dans mon activité principale, je dois obtenir le résultat de la OnPostExecute() dans la AsyncTask. Comment puis-je transmettre ou obtenir le résultat de mon activité principale?

Voici les exemples de codes.

Mon activité principale.

public class MainActivity extends Activity{

    AasyncTask asyncTask = new AasyncTask();

    @Override
    public void onCreate(Bundle aBundle) {
        super.onCreate(aBundle);            

        //Calling the AsyncTask class to start to execute.  
        asyncTask.execute(a.targetServer); 

        //Creating a TextView.
        TextView displayUI = asyncTask.dataDisplay;
        displayUI = new TextView(this);
        this.setContentView(tTextView); 
    }

}

C'est la classe AsyncTask

public class AasyncTask extends AsyncTask<String, Void, String> {

TextView dataDisplay; //store the data  
String soapAction = "http://sample.com"; //SOAPAction header line. 
String targetServer = "https://sampletargeturl.com"; //Target Server.

//SOAP Request.
String soapRequest = "<sample XML request>";    



@Override
protected String doInBackground(String... string) {

String responseStorage = null; //storage of the response

try {


    //Uses URL and HttpURLConnection for server connection. 
    URL targetURL = new URL(targetServer);
    HttpURLConnection httpCon = (HttpURLConnection) targetURL.openConnection();
    httpCon.setDoOutput(true);
    httpCon.setDoInput(true);
    httpCon.setUseCaches(false); 
    httpCon.setChunkedStreamingMode(0);

    //properties of SOAPAction header
    httpCon.addRequestProperty("SOAPAction", soapAction);
    httpCon.addRequestProperty("Content-Type", "text/xml; charset=utf-8"); 
    httpCon.addRequestProperty("Content-Length", "" + soapRequest.length());
    httpCon.setRequestMethod(HttpPost.METHOD_NAME);


    //sending request to the server.
    OutputStream outputStream = httpCon.getOutputStream(); 
    Writer writer = new OutputStreamWriter(outputStream);
    writer.write(soapRequest);
    writer.flush();
    writer.close();


    //getting the response from the server
    InputStream inputStream = httpCon.getInputStream(); 
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);

    int intResponse = httpCon.getResponseCode();

    while ((intResponse = bufferedReader.read()) != -1) {
        byteArrayBuffer.append(intResponse);
    }

    responseStorage = new String(byteArrayBuffer.toByteArray()); 

    } catch (Exception aException) {
    responseStorage = aException.getMessage(); 
    }
    return responseStorage;
}

protected void onPostExecute(String result) {

    aTextView.setText(result);

}       

}   
316
Stella

Facile:

  1. Créez la classe interface, où String output est facultatif ou définissez les variables à renvoyer. 

    public interface AsyncResponse {
        void processFinish(String output);
    }
    
  2. Accédez à votre classe AsyncTask et déclarez l'interface AsyncResponse sous la forme d'un champ:

    public class MyAsyncTask extends AsyncTask<Void, Void, String> {
      public AsyncResponse delegate = null;
    
        @Override
        protected void onPostExecute(String result) {
          delegate.processFinish(result);
        }
     }
    
  3. Dans votre activité principale, vous devez implements interface AsyncResponse.

    public class MainActivity implements AsyncResponse{
      MyAsyncTask asyncTask =new MyAsyncTask();
    
      @Override
      public void onCreate(Bundle savedInstanceState) {
    
         //this to set delegate/listener back to this class
         asyncTask.delegate = this;
    
         //execute the async task 
         asyncTask.execute();
      }
    
      //this override the implemented method from asyncTask
      @Override
      void processFinish(String output){
         //Here you will receive the result fired from async class 
         //of onPostExecute(result) method.
       }
     }
    

METTRE À JOUR

Je ne savais pas que c'était un favori pour beaucoup d'entre vous. Voici donc le moyen simple et pratique d’utiliser interface.

toujours en utilisant le même interface. Pour votre information, vous pouvez combiner cela dans la classe AsyncTask.

dans la classe AsyncTask:

public class MyAsyncTask extends AsyncTask<Void, Void, String> {

  // you may separate this or combined to caller class.
  public interface AsyncResponse {
        void processFinish(String output);
  }

  public AsyncResponse delegate = null;

    public MyAsyncTask(AsyncResponse delegate){
        this.delegate = delegate;
    }

    @Override
    protected void onPostExecute(String result) {
      delegate.processFinish(result);
    }
}

faites ceci dans votre classe Activity

public class MainActivity extends Activity {

   MyAsyncTask asyncTask = new MyAsyncTask(new AsyncResponse(){

     @Override
     void processFinish(String output){
     //Here you will receive the result fired from async class 
     //of onPostExecute(result) method.
     }
  }).execute();

 }

Ou, implémenter à nouveau l'interface sur l'activité 

public class MainActivity extends Activity 
    implements AsyncResponse{

    @Override
    public void onCreate(Bundle savedInstanceState) {

        //execute the async task 
        new MyAsyncTask(this).execute();
    }

    //this override the implemented method from AsyncResponse
    @Override
    void processFinish(String output){
        //Here you will receive the result fired from async class 
        //of onPostExecute(result) method.
    }
}

Comme vous pouvez voir 2 solutions ci-dessus, la première et troisième, il doit créer la méthode processFinish, l'autre, la méthode est à l'intérieur du paramètre caller. La troisième est plus nette car il n'y a pas de classe anonyme imbriquée. J'espère que cela t'aides

Astuce : Changez String output, String response et String result en différents types correspondants pour obtenir différents objets. 

677
HelmiB

Il y a quelques options:

  • Emboîtez la classe AsyncTask dans votre classe Activity. En supposant que vous n’utilisez pas la même tâche dans plusieurs activités, c’est le moyen le plus simple. Tout votre code reste le même, il vous suffit de déplacer la classe de tâches existante pour qu'elle soit une classe imbriquée dans la classe de votre activité.

    public class MyActivity extends Activity {
        // existing Activity code
        ...
    
        private class MyAsyncTask extends AsyncTask<String, Void, String> {
            // existing AsyncTask code
            ...
        }
    }
    
  • Créez un constructeur personnalisé pour votre AsyncTask qui prend une référence à votre Activity. Vous pouvez instancier la tâche avec quelque chose comme new MyAsyncTask(this).execute(param1, param2).

    public class MyAsyncTask extends AsyncTask<String, Void, String> {
        private Activity activity;
    
        public MyAsyncTask(Activity activity) {
            this.activity = activity;
        }
    
        // existing AsyncTask code
        ...
    }
    
23
quietmint

J'ai senti que l'approche ci-dessous est très facile.

J'ai déclaré une interface pour le rappel

public interface AsyncResponse {
    void processFinish(Object output);
}

Ensuite, créé une tâche asynchrone pour répondre à tous les types de demandes parallèles

 public class MyAsyncTask extends AsyncTask<Object, Object, Object> {

    public AsyncResponse delegate = null;//Call back interface

    public MyAsyncTask(AsyncResponse asyncResponse) {
        delegate = asyncResponse;//Assigning call back interfacethrough constructor
    }

    @Override
    protected Object doInBackground(Object... params) {

      //My Background tasks are written here

      return {resutl Object}

    }

    @Override
    protected void onPostExecute(Object result) {
        delegate.processFinish(result);
    }

}

Ensuite, a appelé la tâche asynchrone lorsque vous cliquez sur un bouton dans l'activité Classe.

public class MainActivity extends Activity{

    @Override
    public void onCreate(Bundle savedInstanceState) {

    Button mbtnPress = (Button) findViewById(R.id.btnPress);

    mbtnPress.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() {

                    @Override
                    public void processFinish(Object output) {
                        Log.d("Response From Asynchronous task:", (String) output);

                        mbtnPress.setText((String) output);
                   }
                });

                asyncTask.execute(new Object[] { "Your request to aynchronous task class is giving here.." });


            }
        });

    }



}

Merci

16
Arshad

Vous pouvez essayer ce code dans votre classe principale. Cela a fonctionné pour moi, mais j'ai implémenté des méthodes d'une autre manière

try {
    String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
} 
catch (ExecutionException | InterruptedException ei) {
    ei.printStackTrace();
}
14
Nicu P

Vous pouvez le faire en quelques lignes, il suffit de remplacer onPostExecute lorsque vous appelez votre AsyncTask. Voici un exemple pour vous:

new AasyncTask()
{
    @Override public void onPostExecute(String result)
    {
       // do whatever you want with result 
    }
}.execute(a.targetServer);

J'espère que cela vous a aidé, joyeux codding :)

6
Sa Qada

Cette réponse risque d’être tardive, mais je voudrais mentionner peu de choses lorsque votre Activity dépend de AsyncTask. Cela vous aiderait à prévenir les pannes et la gestion de la mémoire. Comme déjà mentionné dans les réponses ci-dessus, allez avec interface, nous leur disons aussi des rappels. Ils fonctionneront comme un informateur, mais n'enverront jamais la référence strong de Activity ou interface toujours utiliser la référence faible dans ces cas.

Veuillez vous reporter à la capture d'écran ci-dessous pour savoir comment cela peut poser problème.

 enter image description here

Comme vous pouvez le voir, si nous avons démarré AsyncTask avec une référence strong, rien ne garantit que notre Activity/Fragment sera en vie tant que nous n'aurons pas obtenu de données. Mieux vaut utiliser WeakReference dans ces cas-là et cela facilitera également la gestion de la mémoire car nous ne tiendrons jamais la référence forte de notre Activity, il sera alors éligible pour la récupération de place après sa déformation.

Vérifiez le code ci-dessous pour savoir comment utiliser l’impressionnant WeakReference - 

MyTaskInformer.Java Interface qui fonctionnera comme un informateur.

public interface MyTaskInformer {

    void onTaskDone(String output);

}

MySmallAsyncTask.Java AsyncTask pour exécuter une tâche longue, qui utilisera WeakReference.

public class MySmallAsyncTask extends AsyncTask<String, Void, String> {

    // ***** Hold weak reference *****
    private WeakReference<MyTaskInformer> mCallBack;

    public MySmallAsyncTask(MyTaskInformer callback) {
        this.mCallBack = new WeakReference<>(callback);
    }

    @Override
    protected String doInBackground(String... params) {

        // Here do whatever your task is like reading/writing file
        // or read data from your server or any other heavy task

        // Let us suppose here you get response, just return it
        final String output = "Any out, mine is just demo output";

        // Return it from here to post execute
        return output;
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);

        // Here you can't guarantee that Activity/Fragment is alive who started this AsyncTask

        // Make sure your caller is active

        final MyTaskInformer callBack = mCallBack.get();

        if(callBack != null) {
            callBack.onTaskDone(s);
        }
    }
}

MainActivity.Java Cette classe est utilisée pour démarrer ma AsyncTask implémenter interface sur cette classe et override cette méthode obligatoire.

public class MainActivity extends Activity implements MyTaskInformer {

    private TextView mMyTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMyTextView = (TextView) findViewById(R.id.tv_text_view);

        // Start your AsyncTask and pass reference of MyTaskInformer in constructor
        new MySmallAsyncTask(this).execute();
    }

    @Override
    public void onTaskDone(String output) {

        // Here you will receive output only if your Activity is alive.
        // no need to add checks like if(!isFinishing())

        mMyTextView.setText(output);
    }
}
6
Rahul

dans votre Oncreate ():

`

myTask.execute("url");
String result = "";
try {
      result = myTask.get().toString();
} catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
}catch (ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

} `

5
user3691697

Pourquoi les gens rendent-ils les choses si difficiles? 

Cela devrait être suffisant.

N'implémentez pas onPostExecute sur la tâche asynchrone, mais implémentez-le sur l'activité:

public class MainActivity extends Activity 
{

@Override
public void onCreate(Bundle savedInstanceState) {

    //execute the async task 
    MyAsyncTask task = new MyAsyncTask(){
            protected void onPostExecute(String result) {
                //Do your thing
            }       

    }

    task.execute("Param");

}


}
4
bugdayci

Vous pouvez appeler la méthode get() de AsyncTask (ou la méthode surchargée get(long, TimeUnit) ). Cette méthode bloquera jusqu'à ce que la AsyncTask ait terminé son travail, auquel cas elle vous retournera la Result.

Il serait sage de faire un autre travail entre la création/démarrage de votre tâche async et l'appel de la méthode get, sinon vous n'utiliseriez pas la tâche async de manière très efficace.

3
nicholas.hauschild

Salut, tu peux faire quelque chose comme ça:

  1. Créer une classe qui implémente AsyncTask 

    // TASK 
    public class SomeClass extends AsyncTask<Void, Void, String>>
    {
    
        private OnTaskExecutionFinished _task_finished_event;
    
        public interface OnTaskExecutionFinished
        {
            public void OnTaskFihishedEvent(String Reslut);
        }
    
        public void setOnTaskFinishedEvent(OnTaskExecutionFinished _event)
        {
            if(_event != null)
            {
                this._task_finished_event = _event;
            }
        }
    
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
    
        }
    
        @Override
        protected String doInBackground(Void... params)
        {
            // do your background task here ...
    
            return "Done!";
        }
    
        @Override
        protected void onPostExecute(String result)
        {
            super.onPostExecute(result);
            if(this._task_finished_event != null)
            {
                this._task_finished_event.OnTaskFihishedEvent(result);
            }
            else
            {
                Log.d("SomeClass", "task_finished even is null");
            }
        }
    }
    
  2. Ajouter dans l'activité principale

    // MAIN ACTIVITY
    public class MyActivity extends ListActivity
    {
       ...
        SomeClass _some_class = new SomeClass();
        _someclass.setOnTaskFinishedEvent(new _some_class.OnTaskExecutionFinished()
        {
        @Override
        public void OnTaskFihishedEvent(String result)
        {
            Toast.makeText(getApplicationContext(),
                    "Phony thread finished: " + result,
                    Toast.LENGTH_SHORT).show();
        }
    
       });
       _some_class.execute();
       ...
     }
    
2
Oleg Karbushev

Vous pouvez écrire votre propre auditeur. C'est la même chose que HelmiB , mais sa réponse est plus naturelle:

Créer une interface d'écoute:

public interface myAsyncTaskCompletedListener {
    void onMyAsynTaskCompleted(int responseCode, String result);
}

Puis écrivez votre tâche asynchrone:

public class myAsyncTask extends AsyncTask<String, Void, String> {

    private myAsyncTaskCompletedListener listener;
    private int responseCode = 0;

    public myAsyncTask() {
    }

    public myAsyncTask(myAsyncTaskCompletedListener listener, int responseCode) {
        this.listener = listener;
        this.responseCode = responseCode;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }


    @Override
    protected String doInBackground(String... params) {
        String result;
        String param = (params.length == 0) ? null : params[0];
        if (param != null) {
            // Do some background jobs, like httprequest...
            return result;
        }
        return null;
    }

    @Override
    protected void onPostExecute(String finalResult) {
        super.onPostExecute(finalResult);
        if (!isCancelled()) {
            if (listener != null) {
                listener.onMyAsynTaskCompleted(responseCode, finalResult);
            }
        }
    }
}

Enfin, implémentez l'auditeur en activité:

public class MainActivity extends AppCompatActivity implements myAsyncTaskCompletedListener {

    @Override
    public void onMyAsynTaskCompleted(int responseCode, String result) {

        switch (responseCode) {
            case TASK_CODE_ONE: 
                // Do something for CODE_ONE
                break;
            case TASK_CODE_TWO:
                // Do something for CODE_TWO
                break;
            default: 
                // Show some error code
        }        
    }

Et voici comment appeler asyncTask:

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Some other codes...
        new myAsyncTask(this,TASK_CODE_ONE).execute("Data for background job");
        // And some another codes...
}
2
Kuvalya

Créez un membre statique dans votre classe d'activité. Puis assigner la valeur pendant la onPostExecute

Par exemple, si le résultat de votre AsyncTask est une chaîne, créez une chaîne statique publique dans votre activité.

public static String dataFromAsyncTask;

Ensuite, dans la onPostExecute de la AsyncTask, appelez simplement votre classe principale et définissez la valeur.

MainActivity.dataFromAsyncTask = "result blah";

1
mrres1

essaye ça:

public class SomAsyncTask extends AsyncTask<String, Integer, JSONObject> {

    private CallBack callBack;

    public interface CallBack {
        void async( JSONObject jsonResult );
        void sync( JSONObject jsonResult );
        void progress( Integer... status );
        void cancel();
    }

    public SomAsyncTask(CallBack callBack) {
        this.callBack = callBack;
    }

    @Override
    protected JSONObject doInBackground(String... strings) {

        JSONObject dataJson = null;

        //TODO query, get some dataJson

        if(this.callBack != null)
            this.callBack.async( dataJson );// asynchronize with MAIN LOOP THREAD

        return dataJson;

    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

        if(this.callBack != null)
            this.callBack.progress(values);// synchronize with MAIN LOOP THREAD

    }

    @Override
    protected void onPostExecute(JSONObject jsonObject) {
        super.onPostExecute(jsonObject);

        if(this.callBack != null)
            this.callBack.sync(jsonObject);// synchronize with MAIN LOOP THREAD
    }

    @Override
    protected void onCancelled() {
        super.onCancelled();

        if(this.callBack != null)
            this.callBack.cancel();

    }
}

Et exemple d'utilisation:

public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);

         final Context _localContext = getContext();
         SomeAsyncTask.CallBack someCallBack = new SomeAsyncTask.CallBack() {

                @Override
                public void async(JSONObject jsonResult) {//async thread
                    //some async process, e.g. send data to server...
                }

                @Override
                public void sync(JSONObject jsonResult) {//sync thread
                    //get result...

                    //get some resource of Activity variable...
                    Resources resources = _localContext.getResources();
                }

                @Override
                public void progress(Integer... status) {//sync thread
                    //e.g. change status progress bar...
                }

                @Override
                public void cancel() {

                }

            };

            new SomeAsyncTask( someCallBack )
                                .execute("someParams0", "someParams1", "someParams2");

    }
0
amiron

Je le fais fonctionner en utilisant thread et handler/message . Les étapes sont les suivantes:

ProgressDialog loadingdialog;

Créez une fonction pour fermer le dialogue lorsque l'opération est terminée.

   private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        loadingdialog.dismiss();

    }
    };

Codez vos détails d'exécution:

 public void startUpload(String filepath) {
    loadingdialog = ProgressDialog.show(MainActivity.this, "Uploading", "Uploading Please Wait", true);
    final String _path = filepath;
    new Thread() {
        public void run() {
            try {
                UploadFile(_path, getHostName(), getPortNo());
                handler.sendEmptyMessage(0);

            } catch (Exception e) {
                Log.e("threadmessage", e.getMessage());
            }
        }
    }.start();
}
0
RAY

Vous devez utiliser "protocoles" pour déléguer ou fournir des données à la variable 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 lui lorsque cet objet rencontre un événement dans un programme. ( Définition Apple )

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

Voici un exemple complet !!!

0
IgniteCoders

Je suis probablement allé un peu trop loin, mais j’ai fourni des rappels pour le code d’exécution et les résultats. évidemment, pour la sécurité des threads, vous voulez faire attention à ce que vous accédez à votre rappel d’exécution.

L'implémentation AsyncTask:

public class AsyncDbCall<ExecuteType,ResultType> extends AsyncTask<ExecuteType, Void,  
ResultType>
{
    public interface ExecuteCallback<E, R>
    {
        public R execute(E executeInput);
    }
    public interface PostExecuteCallback<R>
    {
        public void finish(R result);
    }

    private PostExecuteCallback<ResultType> _resultCallback = null;
    private ExecuteCallback<ExecuteType,ResultType> _executeCallback = null;


    AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback, PostExecuteCallback<ResultType> postExecuteCallback)
    {
        _resultCallback = postExecuteCallback;
        _executeCallback = executeCallback;
    }

    AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback)
    {
        _executeCallback = executeCallback;
    }

    @Override
    protected ResultType doInBackground(final ExecuteType... params)
    {
        return  _executeCallback.execute(params[0]);
    }

    @Override
    protected void onPostExecute(ResultType result)
    {
        if(_resultCallback != null)
            _resultCallback.finish(result);
    }
}

Un rappel:

 AsyncDbCall.ExecuteCallback<Device, Device> updateDeviceCallback = new 
 AsyncDbCall.ExecuteCallback<Device, Device>()
    {
        @Override
        public Device execute(Device device)
        {
            deviceDao.updateDevice(device);
            return device;
        }
    };

Et enfin l'exécution de la tâche asynchrone:

 new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);
0
Squibly