J'utilise la classe AsyncTask
avec la signature suivante:
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);
}
J'essaie de l'appeler d'une autre classe à travers:
ApiAccess apiObj = new ApiAccess (0, "/User");
// String signupResponse = apiObj.execute(nameValuePairs);
String serverResponse = apiObj.execute(nameValuePairs); //ERROR
Mais ici, je reçois cette erreur:
Type mismatch: cannot convert from AsyncTask<List<NameValuePair>,Integer,String> to String
Pourquoi est-ce quand j'ai spécifié String
comme troisième paramètre dans la ligne d'extension de classe?
Vous pouvez obtenir le résultat en appelant la méthode get () d'AsyhncTask sur la tâche AsyncTask retournée, mais elle la transformera d'une tâche asynchrone en tâche synchrone en attendant d'obtenir le résultat.
String serverResponse = apiObj.execute(nameValuePairs).get();
Puisque vous avez votre AsyncTask dans une classe séparée, vous pouvez créer une classe d'interface et la déclarer dans l'AsyncTask et implémenter votre nouvelle classe d'interface en tant que délégué dans la classe à partir de laquelle vous souhaitez accéder aux résultats. Un bon guide est ici: Comment obtenir le résultat de OnPostExecute () pour l'activité principale car AsyncTask est une classe distincte? .
J'essaierai d'appliquer le lien ci-dessus à votre contexte.
(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");
}
}
}
(Votre classe principale, qui implémente IApiAccessResponse)
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.
}
Je suggérerais d'implémenter un rappel de gestionnaire. Vous passeriez le gestionnaire du fragment (ou de l'activité) à la tâche AsyncTask, que la tâche AsyncTask appellera lorsqu'elle sera terminée. L'AsyncTask peut également renvoyer un objet arbitraire.
Voici un exemple AsyncTask, que j'ai dans son propre fichier (non sous-classé):
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);
}
}
Cet exemple suppose que votre AsyncTask a besoin d'un morceau de Candy et d'un Popsicle. Ensuite, il rendra un dessert à votre fragment.
Vous pouvez construire et exécuter AsyncTask sur une seule ligne à partir de votre fragment avec:
( new MyTask( mFragmentHandler, candyCane, grapePop ) ).execute();
Mais bien sûr, vous devrez d'abord configurer le gestionnaire du fragment (myFragmentHandler). Pour ce faire, votre fragment (ou activité) devrait ressembler à (REMARQUE: "implémente 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;
}
}
Si vous utilisez ces morceaux de code, une pression sur un bouton déclenchera la tâche AsyncTask. Le fragment appelant continuera à s'exécuter pendant le traitement de la tâche AsyncTask. Ensuite, lorsque la tâche AsyncTask est terminée, il enverra un message au fragment disant qu'elle est terminée et passera un objet avec le message. À ce stade, le fragment verra le message et fera tout ce que vous voulez.
Remarque: il peut y avoir des fautes de frappe. Ceci est coupé à partir d'un code très volumineux et compliqué.
Le problème est que lorsque vous appelez Exécuter, l'objet AsyncTask est renvoyé, mais pas encore le résultat. Le résultat est calculé en arrière-plan. Le type du résultat sera finalement une chaîne (comme vous l'avez spécifié) et sera passé à onPostExecute()
.
Vous devez utiliser le AsyncTask
comme suit:
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);
}
}
Notez que dans votre exemple, vous ne renvoyez pas le résultat dans doInBackground()
, ce que vous devriez.