-->

Android AsyncTask don't return correct Result

2020-02-06 11:07发布

问题:

for one of projects i want to use Ksoap with AsyncTask. now in this below code AsyncTask can work correctly but after return result to WSDLHeper i get wronge value. for example Result for this.result in doInBackground method is :

[1, 4674070, {item=3000738; item=TSMS; item=30007227; item=30004444440000; item=30007227001401; item=50004066569100; item=50001717; item=500017171; item=5000171717; item=50001717007227; }]

after return value i'm in tmp = String.valueOf(p.execute()) have :

ir.tsms.wsdl.ProcessTask@417b65e0

in this line:

tmp = String.valueOf(p.execute());

and thats wronge tmp must be have

[1, 4674070, {item=3000738; item=TSMS; item=30007227; item=30004444440000; item=30007227001401; item=50004066569100; item=50001717; item=500017171; item=5000171717; item=50001717007227; }]

to return.

My code:

public class WSDLHelper {
    public SoapObject request;
    public static String call(SoapObject rq){

        String tmp;
        ProcessTask p =new ProcessTask(rq);

        tmp = String.valueOf(p.execute());

        return tmp;
    }

}
class ProcessTask extends AsyncTask<Void, Void, String > {
    SoapObject req1;
    private String result;
    public ProcessTask(SoapObject rq) {
        req1 = rq;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

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

        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.setOutputSoapObject(this.req1);

        AndroidHttpTransport transport = new AndroidHttpTransport(Strings.URL_TSMS);
        transport.debug = true;

        try {
            transport.call(Strings.URL_TSMS + this.req1.getName(), envelope);
            this.result = envelope.getResponse().toString();
        } catch (IOException ex) {
            Log.e("" , ex.getMessage());
        } catch (XmlPullParserException ex) {
            Log.e("" , ex.getMessage());
        }

        if (result.equals(String.valueOf(Integers.CODE_USER_PASS_FALSE))) {
            try {
                throw new TException(PublicErrorList.USERNAME_PASSWORD_ERROR);
            } catch (TException e) {
                e.printStackTrace();
            }

            return null;
        }
        return this.result;
    }

    @Override
    protected void onPostExecute(String result) {

        super.onPostExecute(result);
    }

}

回答1:

You cannot get the return value of AsyncTask by

tmp = String.valueOf(p.execute());

This is because Android app doesn't wait for AsyncTask to return a value to move to next line.

You need to use the onPostExecute() Method to process the return value of an AsyncTask .

You can refer AsyncTask: where does the return value of doInBackground() go? for more syntax and more information.



回答2:

you can't return value from asyncTask at all, you can parse result, do what ever you want inside doInbackground() or in onPostExecute(), if you want more flexibility, you can call a method exist out of the asyncTask passing the result from onPostexecute():

private void continueWithResult(String data){
//do whatever you want with the json passed from onPostExecute()
}

class ProcessTask extends AsyncTask<Void, Void, String > {
:
:
    @Override
    protected void onPostExecute(String result) {
        continueWithResult(result);
    }
:
:

and you really need to read the link posted by JTsunami



回答3:

It seems this question spawned from Mahdi's confusion with the answer here, which formerly suggested using

ProcessTask p = new ProcessTask(...);
String result = p.execute();

This obviously can't work as explained by JTsunami here. Anyway, because of that confusion, the intention of Mahdi here is to create and execute the AsyncTask (asynchronously!) and then return the result of the AsyncTask (synchronously!) when it hasn't received the result yet. The only solution is to handle the result INSIDE onPostExecute(). If you need to pass the result to other objects, like an Activity or Fragment, you have to actively pass the result because execute() and call(...) will never wait for it. A good option is to register a listener by replacing

public static String call(SoapObject request) {
    ProcessTask p =new ProcessTask(request);
    return p.execute();
}

class ProcessTask extends AsyncTask<Void, Void, SoapObject>
    SoapObject request;

    public String ProcessTask(SoapObject rq) {
        request = rq;
    }

    ...

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
    }
}

with

public void String call(SoapObject request, ResultListener listener) {
    ProcessTask p = new ProcessTask(request, listener);
    p.execute();
}

class ProcessTask extends AsyncTask<Void, Void, SoapObject>
    private SoapObject request;
    private ResultListener listener;

    public String ProcessTask(SoapObject rq, ResultListener l) {
        request = rq;
        listener = l;
    }

    ...

    @Override
    protected void onPostExecute(String result) {
        listener.onResult(result);
    }
}

public interface ResultListener {
    void onResult(String result);
}

Now you would call

WSDLHelper.call(-your SoapObject here-, new ResultListener() {
    @Override
    public void onResult(String result) {
        // do whatever you want with the result
    }
});

which will make sure you receive the result asynchronously, but still in the same class that calls the method. Note that the return type of call(...) is void: You have to handle the result inside onResult().