webentwicklung-frage-antwort-db.com.de

Wie bekomme ich das Ergebnis von OnPostExecute () zur Hauptaktivität, weil AsyncTask eine separate Klasse ist?

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

}       

}   
316
Stella

Einfach:

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

677
HelmiB

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
        ...
    }
    
23
quietmint

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

16
Arshad

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();
}
14
Nicu P

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 :)

6
Sa Qada

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.

 enter image description here

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

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

} `

5
user3691697

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

}


}
4
bugdayci

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.

3

Hallo du kannst so etwas machen:

  1. 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");
            }
        }
    }
    
  2. 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();
       ...
     }
    
2
Oleg Karbushev

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...
}
2
Kuvalya

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";

1
mrres1

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

    }
0
amiron

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();
}
0
RAY

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.

Hier ist ein vollständiges Beispiel !!!

0
IgniteCoders

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);
0
Squibly