Подтвердить что ты не робот

Как обрабатывать возвращаемое значение из 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 в качестве третьего параметра в строке расширения класса?

4b9b3361

Ответ 1

Вы можете получить результат, вызвав метод AsyhncTask get() в возвращаемой 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 delegate to your class 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.
}

Ответ 2

Я бы предложил реализовать обратный вызов обработчика. Вы передадите обработчик фрагмента (или активности) в 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 see what we are having for dessert 
            Dessert myDessert = (Dessert) msg.obj;
            break;

        }
        return false;
    }

}

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

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

Ответ 3

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

String serverResponse = apiObj.execute(nameValuePairs); 

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

Ответ 4

Проблема заключается в том, что при вызове 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(), который вы должны.