Как обрабатывать возвращаемое значение из AsyncTask

Я использую класс 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); } 

Я пытаюсь назвать это из другого класса:

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

Но здесь я получаю эту ошибку:

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

Почему это, когда я указал String в качестве третьего параметра в строке расширения класса?

Solutions Collecting From Web of "Как обрабатывать возвращаемое значение из AsyncTask"

Вы можете получить результат, вызвав метод get () AsyhncTask на возвращенной AsyncTask, но он превратит его из асинхронной задачи в синхронную задачу, поскольку он ждет получения результата.

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

Поскольку у вас есть AsyncTask в отдельном классе, вы можете создать класс интерфейса и объявить его в AsyncTask и реализовать свой новый класс интерфейса в качестве делегата в классе, к которому вы хотите получить доступ. Хорошее руководство здесь: Как получить результат OnPostExecute () для основного действия, потому что AsyncTask – это отдельный класс? ,

Я попытаюсь применить вышеуказанную ссылку к вашему контексту.

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

(Ваш основной класс, который реализует 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. } 

Я бы предложил реализовать обратный вызов обработчика. Вы передадите обработчик фрагмента (или активности) в AsyncTask, который AsyncTask вызовет, когда он будет завершен. AsyncTask также может передать произвольный объект.

Вот пример AsyncTask, который у меня есть в его собственном файле (не подклассом):

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

В этом примере предполагается, что вашему AsyncTask нужен кусок Candy и Popsicle. Затем он вернет десерт в ваш фрагмент.

Вы можете построить и запустить AsyncTask в одной строке из вашего фрагмента с помощью:

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

Но, конечно, сначала вам нужно настроить обработчик фрагмента (myFragmentHandler). Чтобы сделать это, ваш фрагмент (или действие) должен выглядеть (ПРИМЕЧАНИЕ: «реализует 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; } } 

Если вы используете эти фрагменты кода, нажатие кнопки вызывает функцию AsyncTask. Вызывающий фрагмент будет продолжать выполняться во время обработки AsyncTask. Затем, когда AsyncTask будет завершен, он отправит сообщение фрагменту, в котором говорится, что оно завершено, и передать объект с сообщением. На этом этапе фрагмент увидит сообщение и сделает все, что захочет.

Примечание: могут быть опечатки. Это вырезано из очень большого и сложного кода.

Пожалуйста, прочитайте AsyncTask . Вы можете получить результат по методу onPostExecute . Вы не можете сделать что-то вроде:

 String serverResponse = apiObj.execute(nameValuePairs); 

Потому что он асинхронный.

Проблема в том, что когда вы вызываете execute, возвращается объект AsyncTask, но не результат. Результат вычисляется в фоновом режиме. Тип результата в конечном итоге будет String (как вы указали) и будет передан onPostExecute() .

Вы должны использовать AsyncTask следующим образом:

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

Обратите внимание, что в вашем примере вы не возвращаете результат в doInBackground() , который вам нужно.