Java 如何处理AsyncTask的返回值

Java 如何处理AsyncTask的返回值,java,android,android-asynctask,Java,Android,Android Asynctask,我正在使用带有以下签名的AsyncTask类: public class ApiAccess extends AsyncTask<List<NameValuePair>, Integer, String> { ... private String POST(List<NameValuePair>[] nameValuePairs){ ... return response; } } protected String doInBackg

我正在使用带有以下签名的
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);
}
但这里我得到了一个错误:

Type mismatch: cannot convert from AsyncTask<List<NameValuePair>,Integer,String> to String
类型不匹配:无法从AsyncTask转换为字符串
为什么我在类扩展行中指定了
String
作为第三个参数?

请阅读。您可以在
onPostExecute
方法上获得结果。你不能这样做:

String serverResponse = apiObj.execute(nameValuePairs); 

因为它是异步的。

您可以通过对返回的AsyncTask调用AsyncTask的get()方法来获得结果,但它会在等待获得结果时将其从异步任务转换为同步任务

String serverResponse = apiObj.execute(nameValuePairs).get();
由于AsyncTask位于一个单独的类中,因此可以创建一个接口类并在AsyncTask中声明它,并在希望从中访问结果的类中作为委托实现新的接口类。这里有一个很好的指南:

我将尝试将上述链接应用于您的上下文

(IApiAccessResponse)

(APICESS)


问题是,当您调用execute时,将返回AsyncTask对象,但还没有返回结果。结果在后台计算。结果的类型最终将是一个字符串(如您指定的),并将传递给
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);
    }
}
公共类ApiAccess扩展异步任务{
...
私有字符串POST(列表[]nameValuePairs){
...
返回响应;
}
受保护的void onPreExecute(){
//这在doInBackground开始之前在主(UI)线程上运行
}
受保护的void onPostExecute(字符串结果){
//这在doInBackground返回后在主(UI)线程上运行
}
受保护的字符串doInBackground(列表…nameValuePairs){
//在另一个后台线程中运行
返回岗位(params);
}
}

请注意,在您的示例中,您没有在
doInBackground()
中返回结果,您应该这样做。

我建议实现处理程序回调。您将把片段(或活动)的处理程序传递给AsyncTask,AsyncTask完成后将调用它。AsyncTask还可以传回任意对象

下面是一个示例AsyncTask,我在它自己的文件中有它(不是子类):

当然,您首先需要设置片段的处理程序(myFragmentHandler)。为此,您的片段(或活动)应该如下所示(注意“implements Handler.Callback”):

如果您使用这些代码,按下按钮将触发异步任务。AsyncTask正在处理时,调用片段将继续执行。然后,当AsyncTask完成时,它将向片段发送一条消息,说明它已完成,并将一个对象与该消息一起传递。此时,片段将看到消息,并执行您想要的任何操作


注意:可能有打字错误。这是从一个非常大和复杂的代码中截取的

但我是从外部调用的,我如何才能在那里得到结果?您可以编写一个回调,由asyncTask(onPostExecute方法)调用并在外部实现。如果有人想要同步执行,不应该使用asyncTask,这是一个坏主意。我知道,但我更想让他了解为什么会出现错误,因为这就是他所问的,我的过程只需要1-3秒,所以这是有帮助的。谢谢(IApiAccessResponse)是要添加到此处的新类吗?方法execute返回
AsyncTask
而不是结果。如果您想从asyncTask返回一些结果或提供一些数据,请使用我认为我们应该在asyncTask中保留一周的handler引用。我不知道你的意思。我认为代码格式不好,所以我尝试修复它。也许一开始并不明显。感谢不莱梅·马特的解决方案。使用此解决方案,我能够修复两个异步任务之间的同步问题。
public interface IApiAccessResponse {
    void postResult(String asyncresult);
}
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");
        }
    } 
}
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.
}
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);
    }
}
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);
    }
}
( new MyTask( mFragmentHandler, candyCane, grapePop ) ).execute();
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;
    }

}