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);
}
}
Facile:
Créez la classe interface
, où String output
est facultatif ou définissez les variables à renvoyer.
public interface AsyncResponse {
void processFinish(String output);
}
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);
}
}
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.
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
...
}
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
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();
}
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 :)
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.
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);
}
}
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();
} `
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");
}
}
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.
Salut, tu peux faire quelque chose comme ça:
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");
}
}
}
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();
...
}
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...
}
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";
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");
}
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();
}
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.
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);