2013-10-27 10 views
17

zu handhaben ich AsyncTask Klasse mit der folgenden Signatur verwenden:Wie Rückgabewert von AsyncTask

public class ApiAccess extends AsyncTask<List<NameValuePair>, Integer, String> { 
    ... 
private String POST(List<NameValuePair>[] nameValuePairs){ 
    ... 
    return response; 
} 
} 

protected String doInBackground(List<NameValuePair>... nameValuePairs) { 
    return POST(params); 
} 

ich es von anderer Klasse bis zu rufen versuchen:

ApiAccess apiObj = new ApiAccess (0, "/User"); 
// String signupResponse = apiObj.execute(nameValuePairs); 
String serverResponse = apiObj.execute(nameValuePairs); //ERROR 

Aber hier bekomme ich dies Fehler:

Type mismatch: cannot convert from AsyncTask<List<NameValuePair>,Integer,String> to String 

Warum ist, dass, wenn ich String als dritter Parameter in der Klasse festgelegt haben Verlängerungslinie?

+0

Die Methode execute gibt die 'AsyncTask' nicht als Ergebnis zurück. Wenn Sie ein Ergebnis aus der asyncTask zurückgeben oder Daten bereitstellen möchten, verwenden Sie [protocols] (http://stackoverflow.com/a/26820666/2835520) – IgniteCoders

Antwort

29

Sie können das Ergebnis erhalten, indem Sie die get() - Methode von AsyhncTask für die zurückgegebene AsyncTask aufrufen, sie wird jedoch von einer asynchronen Task in eine synchrone Task umgewandelt, während sie auf das Ergebnis wartet.

String serverResponse = apiObj.execute(nameValuePairs).get(); 

Da Sie Ihre AsyncTask in einer separaten Klasse haben, können Sie eine Interface-Klasse erstellen und es in der AsyncTask erklären und Ihre neue Interface-Klasse als Delegierter implementieren Sie in der Klasse möchten, aus den Ergebnissen gelangen. Eine gute Anleitung ist hier: How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?.

Ich werde versuchen, den obigen Link auf Ihren Kontext anzuwenden.

(IApiAccessResponse)

public interface IApiAccessResponse { 
    void postResult(String asyncresult); 
} 

(ApiAccess)

public class ApiAccess extends AsyncTask<List<NameValuePair>, Integer, String> { 
... 
    public IApiAccessResponse delegate=null; 
    protected String doInBackground(List<NameValuePair>... nameValuePairs) { 
     //do all your background manipulation and return a String response 
     return response 
    } 

    @Override 
    protected void onPostExecute(String result) { 
     if(delegate!=null) 
     { 
      delegate.postResult(result); 
     } 
     else 
     { 
      Log.e("ApiAccess", "You have not assigned IApiAccessResponse delegate"); 
     } 
    } 
} 

(Ihre Hauptklasse, die IApiAccessResponse implementiert)

ApiAccess apiObj = new ApiAccess (0, "/User"); 
//Assign the AsyncTask's delegate to your class's context (this links your asynctask and this class together) 
apiObj.delegate = this; 
apiObj.execute(nameValuePairs); //ERROR 

//this method has to be implement so that the results can be called to this class 
void postResult(String asyncresult){ 
    //This method will get call as soon as your AsyncTask is complete. asyncresult will be your result. 
} 
+1

Falls jemand eine synchrone Ausführung wünscht, sollte AsyncTask nicht verwendet werden, das ist eine schlechte Idee. –

+3

Ich weiß, aber ich war mehr versucht, ihm Einblick zu geben, warum er den Fehler bekam, da das ist, was er über – frogmanx

0

Bitte lesen Sie AsyncTask. Sie können das Ergebnis auf onPostExecute Methode erhalten. Sie können nichts tun wie:

String serverResponse = apiObj.execute(nameValuePairs); 

weil es async ist.

+0

, aber ich rufe es von außen an, wie kann ich dort Ergebnisse erzielen? – Maven

+0

Sie können ein CallBack schreiben, das von asyncTask (onPostExecute-Methode) aufgerufen und extern implementiert wird. – Devrim

0

Das Problem ist, dass, wenn Sie ausführen nennen, die AsyncTask-Objekt wird zurückgegeben, aber noch nicht das Ergebnis. Das Ergebnis wird im Hintergrund berechnet. Der Typ des Ergebnisses wird schließlich ein String sein (wie Sie angegeben haben) und wird an onPostExecute() übergeben.

Sie sollten die AsyncTask wie folgt verwenden:

public class ApiAccess extends AsyncTask<List<NameValuePair>, Integer, String> { 
    ... 
    private String POST(List<NameValuePair>[] nameValuePairs){ 
    ... 
     return response; 
    } 

    protected void onPreExecute(){ 
     // this is run on the main (UI) thread, before doInBackground starts 
    } 

    protected void onPostExecute (String result){ 
     // this is run on the main (UI) thread, after doInBackground returns 
    } 

    protected String doInBackground(List<NameValuePair>... nameValuePairs) { 
     // run in another, background thread 
     return POST(params); 
    } 
} 

Beachten Sie, dass Sie in Ihrem Beispiel sind in doInBackground(), das Ergebnis der Rückkehr nicht, die Sie sollten.

3

Ich würde vorschlagen, einen Handler Callback zu implementieren. Sie würden den Handler des Fragments (oder der Aktivität) an die AsyncTask übergeben, die die AsyncTask aufrufen wird, wenn sie beendet ist. Die AsyncTask kann auch ein beliebiges Objekt zurückgeben. Hier

ist ein Beispiel AsyncTask, die ich in einer eigenen Datei (nicht subclassed):

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

    private static final String TAG = "MyTask"; 
    private Handler mCallersHandler; 
    private Candy mObject1; 
    private Popsicle mObject2; 

    // Return codes 
    public static final int MSG_FINISHED = 1001; 

    public SaveVideoTask(Handler handler, Candy candyCane, Popsicle grapePop) { 
     this.mCallersHandler = handler; 
     this.mObject1  = candyCane; 
     this.mObject2  = grapePop; 
    } 

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

     // Do all of the processing that you want to do... 
     // You already have the private fields because of the constructor 
     // so you can use mObject1 and mObject2 
     Dessert objectToReturn = mObject1 + mObject2; 

     // Tell the handler (usually from the calling thread) that we are finished, 
     // returning an object with the message 
     mCallersHandler.sendMessage(Message.obtain(mCallersHandler, MSG_FINISHED, objectToReturn)); 

     return (null); 
    } 
} 

Dieses Beispiel geht davon aus, dass Ihr AsyncTask ein Stück Süßigkeit benötigt und ein Eis am Stiel.Dann wird ein Dessert zu deinem Fragment zurückgegeben.

Sie können die AsyncTask in einer Zeile aus dem Fragment konstruieren und laufen mit:

(new MyTask(mFragmentHandler, candyCane, grapePop)).execute(); 

Aber natürlich werden Sie zunächst das Fragment Handler (myFragmentHandler) einrichten müssen. Um dies zu tun, sollte Ihr Fragment (oder Aktivität) aussehen (man beachte die „implementiert Handler.Callback“):

public class MyFragment extends Fragment implements Handler.Callback { 

    private Handler mFragmentHandler; 
    private Candy candyCane; 
    private Popsicle grapePop; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 

     // Standard creation code 
     super.onCreate(savedInstanceState); 
     setRetainInstance(true); 

     // Create a handler for this fragment 
     mFragmentHandler = new Handler(this); 

     // Other stuff... 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, 
      Bundle savedInstanceState) { 

     // Inflate the layout 
     View v = inflater.inflate(R.layout.my_fragment_layout, parent, false); 

     // The candyCane and grapePop don't need to be set up here, but 
     // they MUST be set up before the button is pressed. 
     // Here would be a good place to at least initialize them... 

     // Perhaps you have a button in "my_fragment_layout" that triggers the AsyncTask... 
     Button mButton = (Button) v.findViewById(R.id.mButton); 
     mButton.setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       (new MyTask(mFragmentHandler, candyCane, grapePop)).execute(); 
      } 
     }); 
     return v; 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public boolean handleMessage(Message msg) { 

     switch (msg.what) { 

     case MyTask.MSG_FINISHED: 

      // Let's see what we are having for dessert 
      Dessert myDessert = (Dessert) msg.obj; 
      break; 

     } 
     return false; 
    } 

} 

Wenn Sie diese Teile des Codes zu verwenden, eine Taste drücken Sie die AsyncTask auslösen. Das aufrufende Fragment wird weiterhin ausgeführt, während die AsyncTask verarbeitet. Wenn die AsyncTask beendet ist, sendet sie eine Nachricht an das Fragment, dass sie beendet ist, und übergibt ein Objekt mit der Nachricht. An diesem Punkt wird das Fragment die Nachricht sehen und tun, was Sie wollen.

Hinweis: Es kann Tippfehler geben. Dies ist aus einem sehr großen und komplizierten Code geschnitten.

+0

fragte Ich denke, wir sollten eine Woche Referenz der Handler in AsyncTask – Sayem

+0

Es gibt eine Referenz. Ich bin mir nicht sicher, was du meinst. Ich denke, die Formatierung des Codes war schlecht, also habe ich versucht, es zu beheben. Vielleicht war es anfangs nicht offensichtlich. –

+0

Danke Bremen_matt für diese Lösung. Ich war in der Lage, Synchronisierungsprobleme zwischen zwei Async-Aufgaben mit dieser Lösung zu beheben. –