Ich habe diese zwei Klassen. Meine Hauptaktivität und die, die die AsyncTask
erweitert. Nun muss ich in meiner Hauptaktivität das Ergebnis von der OnPostExecute()
in der AsyncTask
erhalten. Wie kann ich meine Hauptaktivität weitergeben oder erhalten?
Hier sind die Beispielcodes.
Meine Hauptaktivität.
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);
}
}
Dies ist die AsyncTask-Klasse
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);
}
}
Einfach:
Erstellen Sie eine interface
-Klasse, wobei String output
optional ist oder die Variablen sein können, die Sie zurückgeben möchten.
public interface AsyncResponse {
void processFinish(String output);
}
Gehen Sie zu Ihrer AsyncTask
-Klasse und deklarieren Sie das Interface AsyncResponse
als Feld:
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
public AsyncResponse delegate = null;
@Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
}
In Ihrer Hauptaktivität müssen Sie implements
Schnittstelle AsyncResponse
verwenden.
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.
}
}
AKTUALISIEREN
Ich wusste nicht, dass dies für viele von euch ein Favorit ist. Hier ist der einfache und bequeme Weg, interface
zu verwenden.
verwendet immer noch dasselbe interface
. Zu Ihrer Information können Sie dies in der AsyncTask
-Klasse kombinieren.
in AsyncTask
-Klasse:
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);
}
}
tun Sie dies in Ihrer Activity
-Klasse
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();
}
Oder die Schnittstelle erneut für die Aktivität implementieren
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.
}
}
Wie Sie oben zwei Lösungen sehen können, die erste und die dritte, müssen Sie die Methode processFinish
erstellen. Die andere Methode befindet sich im Aufruferparameter. Die dritte ist übersichtlicher, da es keine verschachtelte anonyme Klasse gibt. Hoffe das hilft
Tipp : Ändern Sie String output
, String response
und String result
in verschiedene übereinstimmende Typen, um verschiedene Objekte zu erhalten.
Es gibt einige Möglichkeiten:
Verschachteln Sie die AsyncTask
-Klasse in Ihrer Activity
-Klasse. Angenommen, Sie verwenden nicht dieselbe Aufgabe in mehreren Aktivitäten. Dies ist der einfachste Weg. Der gesamte Code bleibt gleich. Sie verschieben lediglich die vorhandene Taskklasse, sodass sie in der Klasse Ihrer Aktivität eine verschachtelte Klasse ist.
public class MyActivity extends Activity {
// existing Activity code
...
private class MyAsyncTask extends AsyncTask<String, Void, String> {
// existing AsyncTask code
...
}
}
Erstellen Sie einen benutzerdefinierten Konstruktor für Ihr AsyncTask
, der einen Verweis auf Ihr Activity
enthält. Sie würden die Aufgabe mit etwas wie new MyAsyncTask(this).execute(param1, param2)
instanziieren.
public class MyAsyncTask extends AsyncTask<String, Void, String> {
private Activity activity;
public MyAsyncTask(Activity activity) {
this.activity = activity;
}
// existing AsyncTask code
...
}
Ich habe das Gefühl, dass der folgende Ansatz sehr einfach ist.
Ich habe eine Schnittstelle für den Rückruf deklariert
public interface AsyncResponse {
void processFinish(Object output);
}
Dann wurde ein asynchroner Task erstellt, mit dem alle Arten von parallelen Anforderungen beantwortet werden können
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);
}
}
Ruft dann die asynchrone Task auf, wenn Sie auf eine Schaltfläche in der Aktivitätsklasse klicken.
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.." });
}
});
}
}
Vielen Dank
Sie können diesen Code in Ihrer Hauptklasse testen. Das hat bei mir funktioniert, aber ich habe Methoden auf andere Weise implementiert
try {
String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
}
catch (ExecutionException | InterruptedException ei) {
ei.printStackTrace();
}
Sie können dies in ein paar Zeilen tun, indem Sie onPostExecute überschreiben, wenn Sie Ihre AsyncTask aufrufen. Hier ist ein Beispiel für Sie:
new AasyncTask()
{
@Override public void onPostExecute(String result)
{
// do whatever you want with result
}
}.execute(a.targetServer);
Ich hoffe es hat dir geholfen, fröhliches Codding :)
Diese Antwort könnte spät sein, aber ich möchte ein paar Dinge erwähnen, wenn Ihre Activity
von AsyncTask
abhängt. Das würde Ihnen helfen, Abstürze und Speicherverwaltung zu verhindern. Wie bereits in den obigen Antworten erwähnt, gehen die Antworten auf interface
, wir sagen ihnen auch Rückrufe. Sie arbeiten als Informant, senden jedoch niemals strong Referenz von Activity
oder interface
verwenden in diesen Fällen immer weak Referenz.
In der Abbildung unten sehen Sie, wie dies zu Problemen führen kann.
Wie Sie sehen, wenn wir AsyncTask
mit einer strong - Referenz gestartet haben, gibt es keine Garantie, dass unsere Activity
/Fragment
lebendig sein wird, bis wir Daten erhalten. In diesen Fällen ist es also besser, WeakReference
zu verwenden, was auch helfen wird in der Speicherverwaltung, da wir nie die starke Referenz unserer Activity
haben werden, dann wird es nach seiner Verzerrung für die Müllsammlung in Frage kommen.
Schauen Sie sich das Code-Snippet an, um herauszufinden, wie man WeakReference verwendet -
MyTaskInformer.Java
Schnittstelle, die als Informant arbeitet.
public interface MyTaskInformer {
void onTaskDone(String output);
}
MySmallAsyncTask.Java
AsyncTask für lange ausgeführte Aufgaben, die WeakReference
verwenden.
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
Diese Klasse wird verwendet, um meine AsyncTask
-Implementierung interface
für diese Klasse und override
diese obligatorische Methode zu starten.
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);
}
}
in deinem 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();
} `
Warum machen die Leute es so schwer?
Das sollte ausreichen.
Implementieren Sie onPostExecute nicht für die async-Task, sondern implementieren Sie es für Activity:
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");
}
}
Sie können die get()
-Methode von AsyncTask
(oder die überladene get(long, TimeUnit)
) aufrufen. Diese Methode wird blockiert, bis die AsyncTask
ihre Arbeit abgeschlossen hat. Dann wird die Result
zurückgegeben.
Es ist ratsam, zwischen der Erstellung/dem Start Ihrer asynchronen Task und dem Aufruf der get
-Methode andere Aufgaben zu erledigen. Andernfalls verwenden Sie die async-Task nicht sehr effizient.
Hallo du kannst so etwas machen:
Erstellen Sie eine Klasse, die AsyncTask implementiert
// 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");
}
}
}
In Hauptaktivität hinzufügen
// 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();
...
}
Sie können Ihren eigenen Listener schreiben. Es ist dasselbe wie die Antwort von HelmiB , sieht aber natürlicher aus:
Listener-Schnittstelle erstellen:
public interface myAsyncTaskCompletedListener {
void onMyAsynTaskCompleted(int responseCode, String result);
}
Dann schreiben Sie Ihre asynchrone Aufgabe:
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);
}
}
}
}
Implementieren Sie schließlich Listener in Aktivität:
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
}
}
Und so können Sie asyncTask aufrufen:
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...
}
Erstellen Sie ein statisches Mitglied in Ihrer Aktivitätsklasse. Weisen Sie dann den Wert während der onPostExecute
zu.
Wenn das Ergebnis Ihrer AsyncTask beispielsweise eine Zeichenfolge ist, erstellen Sie eine öffentliche statische Zeichenfolge in Ihrer Aktivität
public static String dataFromAsyncTask;
Rufen Sie dann in der Variablen onPostExecute
der AsyncTask einfach einen statischen Aufruf Ihrer Hauptklasse auf und legen Sie den Wert fest.
MainActivity.dataFromAsyncTask = "result blah";
versuche dies:
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();
}
}
Und Anwendungsbeispiel:
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");
}
Ich lasse es funktionieren, indem ich Threading und Handler/message . Benutze. Schritte wie folgt: Deklariere einen Fortschritt-Dialog
ProgressDialog loadingdialog;
Erstellen Sie eine Funktion, um den Dialog zu schließen, wenn der Vorgang abgeschlossen ist.
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
loadingdialog.dismiss();
}
};
Geben Sie Ihre Ausführungsdetails ein:
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();
}
Sie müssen "protocols" verwenden, um Daten an die AsynTask
zu delegieren oder bereitzustellen.
Delegierte und Datenquellen
Ein Delegat ist ein Objekt, das im Auftrag oder in Abstimmung mit einem anderen Objekt handelt, wenn dieses Objekt auf ein Ereignis in einem Programm trifft. ( Apple Definition )
protocols sind Schnittstellen, die einige Methoden zum Delegieren einiger Verhalten definieren.
Wahrscheinlich etwas übertrieben, aber ich habe Rückrufe sowohl für den Ausführungscode als auch für die Ergebnisse bereitgestellt. Aus Sicherheitsgründen möchten Sie natürlich darauf achten, auf welchen Zugriff Sie in Ihrem Rückruf für die Ausführung zugreifen.
Die AsyncTask-Implementierung:
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);
}
}
Ein Rückruf:
AsyncDbCall.ExecuteCallback<Device, Device> updateDeviceCallback = new
AsyncDbCall.ExecuteCallback<Device, Device>()
{
@Override
public Device execute(Device device)
{
deviceDao.updateDevice(device);
return device;
}
};
Und schließlich die Ausführung der asynchronen Aufgabe:
new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);