简体   繁体   English

如何处理AsyncTask的返回值

[英]How to handle return value from AsyncTask

I am using AsyncTask class with the following signature: 我正在使用具有以下签名的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);
}

I am trying to call it from other class through: 我试图从其他类通过以下方式调用它:

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

But here I get this error: 但在这里我得到这个错误:

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

Why is that when i have specified String as the third parameter in Class extension line? 为什么当我指定String作为Class扩展行中的第三个参数时?

You can get the result by calling AsyhncTask's get() method on the returned AsyncTask, but it will turn it from an asynchronous task into a synchronous task as it waits to get the result. 您可以通过在返回的AsyncTask上调用AsyhncTask的get()方法来获得结果,但是当它等待获取结果时,它会将它从异步任务转换为同步任务。

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

Since you have your AsyncTask in a seperate class, you can create an interface class and declare it in the AsyncTask and implement your new interface class as delegate in the class you wish to access the results from. 由于您将AsyncTask放在一个单独的类中,您可以创建一个接口类并在AsyncTask中声明它,并在您希望访问结果的类中将您的新接口类实现为委托。 A good guide is here: How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class? 这里有一个很好的指南: 如何将OnPostExecute()的结果导入主活动,因为AsyncTask是一个单独的类? .

I will attempt to apply the above link to your context. 我将尝试将上述链接应用于您的上下文。

(IApiAccessResponse) (IApiAccessResponse)

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

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

(Your main class, which implements IApiAccessResponse) (您的主类,实现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.
}

I would suggest implementing a Handler Callback. 我建议实现一个Handler Callback。 You would pass the fragment's (or activity's) Handler to the AsyncTask, which the AsyncTask will call when it is finished. 您可以将片段的(或活动的)处理程序传递给AsyncTask,AsyncTask在完成时将调用它。 The AsyncTask can also pass back an arbitrary object. AsyncTask也可以传回一个任意对象。

Here is an example AsyncTask, which I have in its own file (not subclassed): 这是一个示例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);
    }
}

This example assumes that your AsyncTask needs a piece of Candy and a Popsicle. 这个例子假设您的AsyncTask需要一块Candy和一个冰棒。 Then it will return a Dessert to your fragment. 然后它会将一个甜点返回到你的片段。

You can construct and run the AsyncTask in one line from your fragment with: 您可以使用以下代码在片段中构建并运行AsyncTask:

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

But of course, you will first need to set up the fragment's handler (myFragmentHandler). 但是,当然,您首先需要设置片段的处理程序(myFragmentHandler)。 To do this, your fragment (or activity) should look like (NOTE the "implements Handler.Callback"): 为此,您的片段(或活动)应该看起来像(注意“implements 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;
    }

}

If you use these pieces of code, a button press will trigger the AsyncTask. 如果您使用这些代码,按下按钮将触发AsyncTask。 The calling fragment will continue to execute while the AsyncTask is processing. 在AsyncTask处理时,调用片段将继续执行。 Then, when the AsyncTask is finished, it will send a message to the fragment saying that it is finished, and pass an object with the message. 然后,当AsyncTask完成时,它将向片段发送一条消息,告知它已完成,并传递带有该消息的对象。 At this point, the fragment will see the message, and do whatever you want. 此时,片段将看到该消息,并执行您想要的任何操作。

Note: There might be typos. 注意:可能存在拼写错误。 This is cut from a very large and complicated code. 这是从非常大而复杂的代码中删除的。

The problem is that when you call execute, the AsyncTask object is returned, but not the result yet. 问题是,当您调用execute时,将返回AsyncTask对象,但尚未返回结果。 The result is computed in the background. 结果在后台计算。 The type of the result will eventually be a String (as you specified), and will be passed to onPostExecute() . 结果的类型最终将是一个String(如您所指定的),并将传递给onPostExecute()

You should use the AsyncTask as follows: 您应该使用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);
    }
}

Note that in your example you are not returning the result in doInBackground() , which you should. 请注意,在您的示例中,您没有在doInBackground()返回结果,您应该这样做。

Please read AsyncTask . 请阅读AsyncTask You can get result on onPostExecute method. 您可以在onPostExecute方法上获得结果。 You can't do something like : 你做不了类似的事情:

String serverResponse = apiObj.execute(nameValuePairs); 

because it is async. 因为它是异步的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM