Android异步任务中的HTTP POST请求

8
请问有人能告诉我如何使用AsyncTask在后台进行HTTP POST请求,并如何将参数传递给AsyncTask?所有我找到的示例都不够清晰,它们都是关于下载文件的。我正在我的主Activity中运行此代码,我的问题是当代码向服务器发送信息时,应用程序会变慢,就像冻结了2至3秒钟,然后它会继续正常工作,直到下一次发送。该HTTP POST请求向服务器发送四个变量(book、libadd和time),第四个是固定的(name)。
提前感谢您的帮助!
    public void  SticketFunction(double book, double libadd, long time){
        Log.v("log_tag", "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SticketFunction()");
        //HttpClient
        HttpClient nnSticket = new DefaultHttpClient();
        //Response handler
        ResponseHandler<String> res = new BasicResponseHandler();

        HttpPost postMethod = new HttpPost("http://www.books-something.com");


        try {
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(5);

            nameValuePairs.add(new BasicNameValuePair("book", book+""));

            nameValuePairs.add(new BasicNameValuePair("libAss", libass+""));

            nameValuePairs.add(new BasicNameValuePair("Time", time+""));

            nameValuePairs.add(new BasicNameValuePair("name", "jack"));
            //Encode and set entity
            postMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8));
            //Execute 
            //manSticket.execute(postMethod);
            String response =Sticket.execute(postMethod, res).replaceAll("<(.|\n)*?>","");
            if (response.equals("Done")){

                //Log.v("log_tag", "!!!!!!!!!!!!!!!!!! SticketFunction got a DONE!");

            }
            else Log.v("log_tag", "!!!!!!!?????????? SticketFunction Bad or no response: " + response);

        } catch (ClientProtocolException e) {  
            // TODO Auto-generated catch block 
            //Log.v("log_tag", "???????????????????? SticketFunction Client Exception");
        } catch (IOException e) {  
            // TODO Auto-generated catch block
            //Log.v("log_tag", "???????????????????? IO Exception");
        } 
    }

}
2个回答

29

起初,你需要创建一个类,如下所示:

public class AsyncHttpPost extends AsyncTask<String, String, String> {
    interface Listener {
        void onResult(String result);
    }
    private Listener mListener;
    private HashMap<String, String> mData = null;// post data

    /**
     * constructor
     */
    public AsyncHttpPost(HashMap<String, String> data) {
        mData = data;
    }
    public void setListener(Listener listener) {
        mListener = listener;
    }

    /**
     * background
     */
    @Override
    protected String doInBackground(String... params) {
        byte[] result = null;
        String str = "";
        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(params[0]);// in this case, params[0] is URL
        try {
            // set up post data
            ArrayList<NameValuePair> nameValuePair = new ArrayList<NameValuePair>();
            Iterator<String> it = mData.keySet().iterator();
            while (it.hasNext()) {
                String key = it.next();
                nameValuePair.add(new BasicNameValuePair(key, mData.get(key)));
            }

            post.setEntity(new UrlEncodedFormEntity(nameValuePair, "UTF-8"));
            HttpResponse response = client.execute(post);
            StatusLine statusLine = response.getStatusLine();
            if(statusLine.getStatusCode() == HttpURLConnection.HTTP_OK){
                result = EntityUtils.toByteArray(response.getEntity());
                str = new String(result, "UTF-8");
            }
        }
        catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        catch (Exception e) {
        }
        return str;
    }

    /**
     * on getting result
     */
    @Override
    protected void onPostExecute(String result) {
        // something...
        if (mListener != null) {
            mListener.onResult(result)
        }
    }
}

现在,你只需要编写类似以下的几行代码:

HashMap<String, String> data = new HashMap<String, String>();
data.put("key1", "value1");
data.put("key2", "value2");
AsyncHttpPost asyncHttpPost = new AsyncHttpPost(data);
asyncHttpPost.setListener(new AsyncHttpPost.Listener(){
    @Override
    public void onResult(String result) {
        // do something, using return value from network
    }
});
asyncHttpPost.execute("http://example.com");

1
很棒的解决方案!只需将其放入Java文件中并运行即可。这是我见过的最简单的异步发布方式。 - StanleyZheng
如何访问具有 AsyncHttpPost 实例的类中的结果? - yatanadam
非常好用,谢谢。我之前看了很多不同的例子,但这个是迄今为止最好的一个,而且它能够正常工作。谢谢你。 - Maytham Fahmi
Android 6.0移除了HttpClient,现在应该使用HttpURLConnection。 - Pete

3

首先,我不建议在AsyncTask中进行Http请求,您最好尝试使用Service。回到如何将参数传递到AsyncTask的问题上,当您声明它时,可以像这样定义每个AsyncTask的Object类。

public AsyncTask <Params,Progress,Result> {

}

在您的任务中,您应该按照以下步骤进行。
public MyTask extends<String,Void,Void>{

public Void doInBackground(String... params){//those Params are String because it's declared like that

}

}

要使用它,非常简单。
new MyTask().execute("param1","param2","param3")

什么是服务,为什么您建议使用它? - aanders77
有关Service的信息很丰富,主要区别在于Service不附加到Activity上,运行在后台但仍在主线程中。还有另一种类型的Service称为IntentService,它具有在另一个线程中运行的方法。根据情况,我尝试在进行Http请求时使用Service。 - Necronet
好的,但是为什么你更喜欢使用服务呢?它更安全、更快速、更容易或其他原因? - aanders77
1
其中一个主要原因是异步任务是与活动相关的,这意味着一个任务不能离开上下文而存在。一旦活动完成(finish()),任务也将被删除,这意味着您的HttpCalled可能已经成功或失败,但您只是浪费了用户资源在您甚至不会使用的东西上;至于服务,您必须使用stopSelf、stopService或从每个上下文中解除绑定才能显式地销毁它,以此来更安全地进行操作。有关更多信息,请访问http://www.youtube.com/watch?v=xHXn3Kg2IQE。 - Necronet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接